SQL 服务器:LAG 多个空值

SQL Server : LAG multiple Nulls

我正在尝试用下面的 table 来“填空”。

我创建了一个 PDF reader,它生成了一个 JSON 文件,我已将其处理成以下格式。

更改源数据或使用辅助 table 作为助手的范围很小,因为这是为了处理以前未“看到”的新数据。

我需要帮助的是填写 ClassGroup 列。我的意思是 Class 列的最后一行总是有一个值,我需要重复(向上)直到它在列中遇到非空值。然后它需要重复这个值,直到遇到下一个非空白等等。

同样,Group Column 需要相同的解决方案,但从第一行开始向下。

我已经尝试使用默认值 LAG() LEAD() 等,但它无法处理多个 nulls.

我还需要 Group 列在不为空时显示 class 值。

我看过 cte 的,但对它们不是很熟悉,今天让自己陷入了困境!

感谢任何帮助。

当前数据

ID, Class, Group, Total, Account
1, null, INCOME, null, Fencing
2, null, null, null, Crop
3, Net Income, null, null, Net Income
4, null, Farm Expenditure, null, Irrigation
5, null, null, null, electricity
6, Surplus, null, null, Surplus
7, null, GST, null, GST
8, Closing Balance, null, null, Closing Balance

我想要的

ID, Class, Group, Total, Account
1, Net Income, INCOME, null, Fencing
2, Net Income, INCOME, null, Crop
3, Net Income, INCOME, null, Net Income
4, Surplus, Farm Expenditure, null, Irrigation
5, Surplus, Farm Expenditure, null, electricity
6, Surplus, Farm Expenditure, null, Surplus
7, Closing Balance, GST, null, GST
8, Closing Balance, GST, null, Closing Balance

这会根据您提供的数据为您提供所需的输出。在您的示例数据中,每个“class”中只有一个“组”,但看起来每个 class 可能有多个组?如果是这样的话,会稍微复杂一点,但是原理是一样的。

CREATE TABLE #data (ID INT, Class VARCHAR(50), [Group] VARCHAR(50), Total INT, Account VARCHAR(50));
INSERT INTO #data(ID, Class, [Group], Total, Account) VALUES
(1, null, 'INCOME', null, 'Fencing'),
(2, null, null, null, 'Crop'),
(3, 'Net Income', null, null, 'Net Income'),
(4, null, 'Farm Expenditure', null, 'Irrigation'),
(5, null, null, null, 'electricity'),
(6, 'Surplus', null, null, 'Surplus'),
(7, null, 'GST', null, 'GST'),
(8, 'Closing Balance', null, null, 'Closing Balance');

-- Find the break points that signify the end of a Class
WITH breaks as(
    SELECT IIF(Class IS NOT NULL, 1, 0) AS breakpoint, ID, Class, [Group], Total, Account 
    FROM #data
),
-- count the breakpoints passed so each group will have a number we can group by
grp AS (
SELECT ISNULL(SUM(breakpoint) OVER (ORDER BY ID ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) AS grp, 
    ID,Class,[Group],Total,Account
FROM breaks
)
SELECT MAX(grp.Class) OVER (PARTITION BY grp.grp) AS Class,
    MAX(grp.[Group]) OVER (PARTITION BY grp.grp) AS [Group],
    grp.Total,
    grp.Account
FROM grp

感谢 James,我现在调整了他的代码以提供正确的组,因为 class 和组需要不同的逻辑。

-- Find the break points that signify the end of a Class
WITH classbreaks as(
    SELECT IIF(Class IS NOT NULL, 1, 0) AS breakpoint, ID, Class, [Group], Total, Account 
    FROM [PedGroup_db].[dbo].[Cashflow]
),

-- Find the break points that signify the end of a Group
grpbreaks as(
    SELECT IIF([Group] IS NOT NULL, 1, 0) AS breakpoint, ID, Class, [Group], Total, Account 
    FROM [PedGroup_db].[dbo].[Cashflow]
),

-- count the breakpoints passed so each class will have a number we can group by
clss AS (
SELECT ISNULL(SUM(breakpoint) OVER (ORDER BY ID ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) AS grp, 
    ID,Class,[Group],Total,Account
FROM classbreaks

),

-- count the breakpoints passed so each group will have a number we can group by
grp AS (
SELECT ISNULL(SUM(breakpoint) OVER (ORDER BY ID),0) AS grp, 
    ID,Class,[Group],Total,Account
FROM grpbreaks

)

--join the two sub queries together on ID
SELECT MAX(clss.Class) OVER (PARTITION BY clss.grp) AS Class,
    case when clss.Class = grp.Account Then grp.Account else MAX(grp.[Group]) OVER (PARTITION BY grp.grp) end AS [Group],
    grp.Total,
    grp.Account
FROM clss left join grp on grp.ID = clss.ID