在 SQL 表中创建层次结构

问题描述 投票:0回答:1

我目前正在尝试在不包含此信息的表上建立父子关系。

就是一个金融账号列表和一个对应的类型,就是这样

虽然现在有一个逻辑,头账户将利润和损失账户分组,最后是总计。标题可以嵌套,总计也可以在此逻辑中形成父子结构是我当前的任务

我已经对应该导致父帐户切换的更改进行了排名。但是我有点坚持构建我的递归查询以一直移动到我想要的输出。

目前我在这个水平(简化示例)

WITH accounts AS (
    SELECT 
        accountNumber, accountType

    FROM (VALUES
        (1000, 'heading'),
        (1001, 'heading'),
        (1010, 'profitAndLoss'),
        (1020, 'profitAndLoss'),
        (1021, 'profitAndLoss'),
        (1025, 'profitAndLoss'),
        (1099, 'totalFrom'),
        (1300, 'heading'),
        (1310, 'profitAndLoss'),
        (1320, 'profitAndLoss'),
        (1321, 'profitAndLoss'),
        (1399, 'totalFrom'),
        (2000, 'totalFrom'),
        (2200, 'heading'),
        (2210, 'profitAndLoss'),
        (2211, 'profitAndLoss')
    ) AS t(accountNumber, accountType)
),

rankedAccounts AS (
    SELECT
        *,
        COALESCE(
            CASE WHEN LAG(accountNumber) OVER(ORDER BY accountNumber) IS NULL THEN 0 END,
            CASE WHEN accountType IN ('heading', 'headingStart') AND LAG(accountType) OVER (ORDER BY accountNumber) IN ('heading', 'headingStart') AND LAG(accountType, 2) OVER (ORDER BY accountNumber) IS NULL THEN 1 END,
            CASE WHEN accountType IN ('heading', 'headingStart') AND LAG(accountType) OVER (ORDER BY accountNumber) IN ('heading', 'headingStart') THEN 0 END,
            CASE WHEN accountType IN ('profitAndLoss', 'status') AND LAG(accountType) OVER (ORDER BY accountNumber) IN ('heading', 'headingStart') THEN 1 END,
            CASE WHEN accountType IN ('heading', 'headingStart') AND LAG(accountType) OVER (ORDER BY accountNumber) IN ('totalFrom', 'sumInterval') AND LAG(accountType, 2) OVER (ORDER BY accountNumber) IN ('totalFrom', 'sumInterval') THEN 0 END,
            CASE WHEN accountType IN ('heading', 'headingStart') AND LAG(accountType) OVER (ORDER BY accountNumber) IN ('totalFrom', 'sumInterval') AND LAG(accountType, 2) OVER (ORDER BY accountNumber) IN ('profitAndLoss', 'status') THEN -1 END,
            CASE WHEN accountType IN ('totalFrom', 'sumInterval') AND LAG(accountType) OVER (ORDER BY accountNumber) IN ('totalFrom', 'sumInterval') THEN -1 END,
            0
        ) Rank

    FROM
        accounts
),

sumRank AS (
    SELECT 
        accountNumber,
        accountType,
        SUM(Rank) OVER (ORDER BY rankedAccounts.accountNumber) sumRank
    
    FROM rankedAccounts
)

SELECT
    *

FROM
    sumRank

此查询的结果数据如下

我想要的输出看起来像这样

我可以在 python 中使用一个非常简单的循环轻松完成此操作,但我无法在 T-SQL 中全神贯注

accountDictList = [
    {'accountNumber': 1000, 'accountType':'heading', 'sumRank':0},
    {'accountNumber': 1001, 'accountType':'heading', 'sumRank':1},
    {'accountNumber': 1010, 'accountType':'profitAndLoss', 'sumRank':2},
    {'accountNumber': 1020, 'accountType':'profitAndLoss', 'sumRank':2},
    {'accountNumber': 1021, 'accountType':'profitAndLoss', 'sumRank':2},
    {'accountNumber': 1025, 'accountType':'profitAndLoss', 'sumRank':2},
    {'accountNumber': 1099, 'accountType':'totalFrom', 'sumRank':2},
    {'accountNumber': 1300, 'accountType':'heading', 'sumRank':1},
    {'accountNumber': 1310, 'accountType':'profitAndLoss', 'sumRank':2},
    {'accountNumber': 1320, 'accountType':'profitAndLoss', 'sumRank':2},
    {'accountNumber': 1321, 'accountType':'profitAndLoss', 'sumRank':2},
    {'accountNumber': 1399, 'accountType':'totalFrom', 'sumRank':2},
    {'accountNumber': 2000, 'accountType':'totalFrom', 'sumRank':1},
    {'accountNumber': 2200, 'accountType':'heading', 'sumRank':1},
    {'accountNumber': 2210, 'accountType':'profitAndLoss', 'sumRank':2},
    {'accountNumber': 2211, 'accountType':'profitAndLoss', 'sumRank':2},
]

for i, account in enumerate(accountDictList):
    try:
        if i == 0:
            parent = None
        elif account['sumRank'] > accountDictList[i-1]['sumRank']:
            grandparent = parent
            parent = accountDictList[i-1]['accountNumber']
        elif account['sumRank'] < accountDictList[i-1]['sumRank']:
            parent = grandparent
    except:
        parent = parent

    print(account, parent)

导致所需的输出

sql recursion hierarchy
1个回答
0
投票

在 Python 中你有变量,在 sql 中没有,所以你需要子查询来获取想要的信息

WITH accounts AS (
    SELECT 
        accountNumber, accountType

    FROM (VALUES
        (1000, 'heading'),
        (1001, 'heading'),
        (1010, 'profitAndLoss'),
        (1020, 'profitAndLoss'),
        (1021, 'profitAndLoss'),
        (1025, 'profitAndLoss'),
        (1099, 'totalFrom'),
        (1300, 'heading'),
        (1310, 'profitAndLoss'),
        (1320, 'profitAndLoss'),
        (1321, 'profitAndLoss'),
        (1399, 'totalFrom'),
        (2000, 'totalFrom'),
        (2200, 'heading'),
        (2210, 'profitAndLoss'),
        (2211, 'profitAndLoss')
    ) AS t(accountNumber, accountType)
),

rankedAccounts AS (
    SELECT
        *,
        COALESCE(
            CASE WHEN LAG(accountNumber) OVER(ORDER BY accountNumber) IS NULL THEN 0 END,
            CASE WHEN accountType IN ('heading', 'headingStart') AND LAG(accountType) OVER (ORDER BY accountNumber) IN ('heading', 'headingStart') AND LAG(accountType, 2) OVER (ORDER BY accountNumber) IS NULL THEN 1 END,
            CASE WHEN accountType IN ('heading', 'headingStart') AND LAG(accountType) OVER (ORDER BY accountNumber) IN ('heading', 'headingStart') THEN 0 END,
            CASE WHEN accountType IN ('profitAndLoss', 'status') AND LAG(accountType) OVER (ORDER BY accountNumber) IN ('heading', 'headingStart') THEN 1 END,
            CASE WHEN accountType IN ('heading', 'headingStart') AND LAG(accountType) OVER (ORDER BY accountNumber) IN ('totalFrom', 'sumInterval') AND LAG(accountType, 2) OVER (ORDER BY accountNumber) IN ('totalFrom', 'sumInterval') THEN 0 END,
            CASE WHEN accountType IN ('heading', 'headingStart') AND LAG(accountType) OVER (ORDER BY accountNumber) IN ('totalFrom', 'sumInterval') AND LAG(accountType, 2) OVER (ORDER BY accountNumber) IN ('profitAndLoss', 'status') THEN -1 END,
            CASE WHEN accountType IN ('totalFrom', 'sumInterval') AND LAG(accountType) OVER (ORDER BY accountNumber) IN ('totalFrom', 'sumInterval') THEN -1 END,
            0
        ) Rank

    FROM
        accounts
),

sumRank AS (
    SELECT 
        accountNumber,
        accountType,
        SUM(Rank) OVER (ORDER BY rankedAccounts.accountNumber) sumRank
    
    FROM rankedAccounts
)

SELECT
    *,
 CASE WHEN sumrank = 0 then NULL
  WHEN sumrank = 1 THEN ( SELECT accountNumber FROM sumRank WHERE sumRank = 0)
  ELSE ( SELECT accountNumber FROM sumRank WHERE sumRank = 1 AND accountNumber < s1.accountNumber ORDER BY accountnumber DESC LIMIT 1)
  END parent
FROM
    sumRank s1

账号 账户类型 总排名 家长
1000 标题 0
1001 标题 1 1000
1010 利润和损失 2 1001
1020 利润和损失 2 1001
1021 利润和损失 2 1001
1025 利润和损失 2 1001
1099 总计 2 1001
1300 标题 1 1000
1310 利润和损失 2 1300
1320 利润和损失 2 1300
1321 利润和损失 2 1300
1399 总计 2 1300
2000 总计 1 1000
2200 标题 1 1000
2210 利润和损失 2 2200
2211 利润和损失 2 2200

小提琴

© www.soinside.com 2019 - 2024. All rights reserved.