SQL 中的棘手分区
Tricky partition in SQL
我有一个table这样的
RID ID DTE FLAG AMT SUMAMT
1 1 2020-07-03 02:52:15.480 Y 10 NULL
2 1 2020-07-04 02:52:15.480 N 10 NULL
3 1 2020-07-05 02:52:15.480 N 10 NULL
4 1 2020-07-06 02:52:15.480 Y 10 NULL
5 1 2020-07-13 02:52:15.480 Y 10 NULL
6 2 2020-07-06 02:52:15.480 N 10 NULL
7 2 2020-07-13 02:52:15.480 Y 10 NULL
我需要这样的结果
RID ID DTE FLAG AMT SUMAMT
1 1 2020-07-03 02:52:15.480 Y 10 10
2 1 2020-07-04 02:52:15.480 N 10 NULL
3 1 2020-07-05 02:52:15.480 N 10 NULL
4 1 2020-07-06 02:52:15.480 Y 10 30
5 1 2020-07-13 02:52:15.480 Y 10 10
6 2 2020-07-06 02:52:15.480 N 10 NULL
7 2 2020-07-13 02:52:15.480 Y 10 20
我在这里需要做的就是更新 'Y' FLAG 行项目的 SUMAMT 列。这里的条件是每当我们找到 'Y' FLAG 时,我们需要根据 DTE 检查过去是否有任何 'N' 标记的行项目,如果是,我们需要对该行项目进行 AMT 并需要总结并更新SUMAMT。
SELECT RID,ID,DTE,FLAG,AMT,SUM(AMT) OVER (PARTITION BY ID ORDER BY ID,DTE) FROM #T
我试过上面的查询,它给出了 运行 总数,我不明白如何制作如下所述的分区...
RID ID DTE FLAG AMT SUMAMT
1 1 2020-07-03 02:52:15.480 Y 10 10
2 1 2020-07-04 02:52:15.480 N 10 NULL
3 1 2020-07-05 02:52:15.480 N 10 NULL
4 1 2020-07-06 02:52:15.480 Y 10 30
5 1 2020-07-13 02:52:15.480 Y 10 10
6 2 2020-07-06 02:52:15.480 N 10 NULL
7 2 2020-07-13 02:52:15.480 Y 10 20
查询以创建 table 并插入数据...
CREATE TABLE #T
(
RID INT IDENTITY(1, 1),
ID INT,
DTE DATETIME,
FLAG VARCHAR(1),
AMT INT,
SUMAMT INT
)
INSERT INTO #T (ID, DTE, FLAG, AMT)
VALUES (1, GETDATE() - 10, 'Y', 10),
(1, GETDATE() - 9, 'N', 10),
(1, GETDATE() - 8, 'N', 10),
(1, GETDATE() - 7, 'Y', 10),
(1, GETDATE(), 'Y', 10),
(2, GETDATE() - 7, 'N', 10),
(2, GETDATE(), 'Y', 10)
感谢您提供样本数据。很有帮助。
在下面的查询中,我们将数据分成两部分:
- 标记'Y'
- 标记'N'
现在,我们计算落在两个 'Y' 标志之间的标志 'N' 的所有行的总和。对于标记 'N' 行,没有计算。
SELECT t.RID, t.id, t.dte, t.amt,t.flag, isnull(t.amt+ot.sum_amt,amt)
from
(SELECT
RID,ID, DTE, ISNULL(LAG(DTE,1) OVER(PARTITION BY ID ORDER BY DTE),'19000101') AS Prev_Yes
, DTE as Current_Yes
,amt
,flag
FROM #t as cr WHERE Flag = 'Y') as t
OUTER APPLY
(SELECT SUM(AMT) FROM #t
WHERE flag = 'N'
AND DTE > t.Prev_Yes AND DTE < t.Current_Yes
and ID = t.id) as ot(sum_amt)
UNION ALL
SELECT RID, id, dte, amt,flag, NULL AS SUM_AMT
FROM #t
WHERE flag = 'N'
ORDER BY rid
+-----+----+-------------------------+-----+------+------------------+
| RID | id | dte | amt | flag | (No column name) |
+-----+----+-------------------------+-----+------+------------------+
| 1 | 1 | 2020-07-03 09:35:10.513 | 10 | Y | 10 |
| 2 | 1 | 2020-07-04 09:35:10.513 | 10 | N | NULL |
| 3 | 1 | 2020-07-05 09:35:10.513 | 10 | N | NULL |
| 4 | 1 | 2020-07-06 09:35:10.513 | 10 | Y | 30 |
| 5 | 1 | 2020-07-13 09:35:10.513 | 10 | Y | 10 |
| 6 | 2 | 2020-07-06 09:35:10.513 | 10 | N | NULL |
| 7 | 2 | 2020-07-13 09:35:10.513 | 10 | Y | 20 |
+-----+----+-------------------------+-----+------+------------------+
我有一个table这样的
RID ID DTE FLAG AMT SUMAMT
1 1 2020-07-03 02:52:15.480 Y 10 NULL
2 1 2020-07-04 02:52:15.480 N 10 NULL
3 1 2020-07-05 02:52:15.480 N 10 NULL
4 1 2020-07-06 02:52:15.480 Y 10 NULL
5 1 2020-07-13 02:52:15.480 Y 10 NULL
6 2 2020-07-06 02:52:15.480 N 10 NULL
7 2 2020-07-13 02:52:15.480 Y 10 NULL
我需要这样的结果
RID ID DTE FLAG AMT SUMAMT
1 1 2020-07-03 02:52:15.480 Y 10 10
2 1 2020-07-04 02:52:15.480 N 10 NULL
3 1 2020-07-05 02:52:15.480 N 10 NULL
4 1 2020-07-06 02:52:15.480 Y 10 30
5 1 2020-07-13 02:52:15.480 Y 10 10
6 2 2020-07-06 02:52:15.480 N 10 NULL
7 2 2020-07-13 02:52:15.480 Y 10 20
我在这里需要做的就是更新 'Y' FLAG 行项目的 SUMAMT 列。这里的条件是每当我们找到 'Y' FLAG 时,我们需要根据 DTE 检查过去是否有任何 'N' 标记的行项目,如果是,我们需要对该行项目进行 AMT 并需要总结并更新SUMAMT。
SELECT RID,ID,DTE,FLAG,AMT,SUM(AMT) OVER (PARTITION BY ID ORDER BY ID,DTE) FROM #T
我试过上面的查询,它给出了 运行 总数,我不明白如何制作如下所述的分区...
RID ID DTE FLAG AMT SUMAMT
1 1 2020-07-03 02:52:15.480 Y 10 10
2 1 2020-07-04 02:52:15.480 N 10 NULL
3 1 2020-07-05 02:52:15.480 N 10 NULL
4 1 2020-07-06 02:52:15.480 Y 10 30
5 1 2020-07-13 02:52:15.480 Y 10 10
6 2 2020-07-06 02:52:15.480 N 10 NULL
7 2 2020-07-13 02:52:15.480 Y 10 20
查询以创建 table 并插入数据...
CREATE TABLE #T
(
RID INT IDENTITY(1, 1),
ID INT,
DTE DATETIME,
FLAG VARCHAR(1),
AMT INT,
SUMAMT INT
)
INSERT INTO #T (ID, DTE, FLAG, AMT)
VALUES (1, GETDATE() - 10, 'Y', 10),
(1, GETDATE() - 9, 'N', 10),
(1, GETDATE() - 8, 'N', 10),
(1, GETDATE() - 7, 'Y', 10),
(1, GETDATE(), 'Y', 10),
(2, GETDATE() - 7, 'N', 10),
(2, GETDATE(), 'Y', 10)
感谢您提供样本数据。很有帮助。
在下面的查询中,我们将数据分成两部分:
- 标记'Y'
- 标记'N'
现在,我们计算落在两个 'Y' 标志之间的标志 'N' 的所有行的总和。对于标记 'N' 行,没有计算。
SELECT t.RID, t.id, t.dte, t.amt,t.flag, isnull(t.amt+ot.sum_amt,amt)
from
(SELECT
RID,ID, DTE, ISNULL(LAG(DTE,1) OVER(PARTITION BY ID ORDER BY DTE),'19000101') AS Prev_Yes
, DTE as Current_Yes
,amt
,flag
FROM #t as cr WHERE Flag = 'Y') as t
OUTER APPLY
(SELECT SUM(AMT) FROM #t
WHERE flag = 'N'
AND DTE > t.Prev_Yes AND DTE < t.Current_Yes
and ID = t.id) as ot(sum_amt)
UNION ALL
SELECT RID, id, dte, amt,flag, NULL AS SUM_AMT
FROM #t
WHERE flag = 'N'
ORDER BY rid
+-----+----+-------------------------+-----+------+------------------+
| RID | id | dte | amt | flag | (No column name) |
+-----+----+-------------------------+-----+------+------------------+
| 1 | 1 | 2020-07-03 09:35:10.513 | 10 | Y | 10 |
| 2 | 1 | 2020-07-04 09:35:10.513 | 10 | N | NULL |
| 3 | 1 | 2020-07-05 09:35:10.513 | 10 | N | NULL |
| 4 | 1 | 2020-07-06 09:35:10.513 | 10 | Y | 30 |
| 5 | 1 | 2020-07-13 09:35:10.513 | 10 | Y | 10 |
| 6 | 2 | 2020-07-06 09:35:10.513 | 10 | N | NULL |
| 7 | 2 | 2020-07-13 09:35:10.513 | 10 | Y | 20 |
+-----+----+-------------------------+-----+------+------------------+