I D*_*son 6 t-sql sql-server-2016
如何获取组(Acc、TranType)的最小值,但过滤掉 Acc 组前面行中使用的任何最小值。前面的行将定义为 Acc asc,TranType asc。
PosCancelID 应该只在每个 Acc 组出现一次。但是相同的 PosCancelID 可能出现在数据集中的另一个 Acc Group 中。
因此,对于给定的数据集:
Acc | TranType | PosCancelID
100 1 2
808 1 5
808 1 4
808 2 5
808 2 4<--To be filtered from min calc as it min for (808,1)
813 2 3
813 4 3<--To be filtered from min calc as it min for (813,2)
809 1 3
809 1 4
809 2 3<--To be filtered from min calc as (809,1) uses it
809 2 4
809 3 4<--To be filtered from min calc as (809,2) uses it
Run Code Online (Sandbox Code Playgroud)
我应该得到:
Acc | TranType | PosCancelID
100 1 2
808 1 4
808 2 5
813 2 3
809 1 3
809 2 4
SELECT ACC, TranType, min(maxPreceeding) as ActualCancelID
FROM
(
SELECT ACC, TranType,
MAX(m.posCancelID) OVER (PARTITION BY m.ACC
ORDER BY m.TranType, m.posCancelID
ROWS UNBOUNDED PRECEDING) as maxPreceeding
FROM MCancel as m
) AS x
GROUP BY ACC, TranType
Run Code Online (Sandbox Code Playgroud)
上面的查询几乎给了我我想要的但没有过滤 acc = 813。所以我知道必须有更好的(实际上应用过滤器来删除以前的最小值)方法。
相当棘手的问题。这是一个递归解决方案:
WITH
rcte AS
( SELECT TOP (1)
Acc, TranType, posCancelID,
CAST('=' + CAST(posCancelID AS VARCHAR(20)) + '=' AS VARCHAR(MAX)) AS IDs
FROM
MCancel
ORDER BY
Acc, TranType, posCancelID
UNION ALL
SELECT
Acc, TranType, posCancelID,
CAST(IDs + CAST(posCancelID AS VARCHAR(20)) + '=' AS VARCHAR(MAX))
FROM
( SELECT
m.*,
r.IDs,
ROW_NUMBER() OVER (ORDER BY m.Acc, m. TranType, m.PosCancelID) AS rn
FROM
rcte AS r
JOIN MCancel AS m
ON (m.Acc = r.Acc AND m.TranType > r.TranType)
OR (m.Acc > r.Acc)
WHERE
r.IDs NOT LIKE ('%=' + CAST(m.posCancelID AS VARCHAR(20)) + '=%')
) AS mc
WHERE
rn = 1
)
SELECT Acc, TranType, posCancelID
FROM rcte
ORDER BY Acc, TranType ;
Run Code Online (Sandbox Code Playgroud)
该解决方案假定 aposCancelID不应在结果集中出现两次。如果要求是它们不应在同一Acc组中出现两次 ,则解决方案需要稍作调整:
WITH rcte AS
( SELECT
Acc, TranType, posCancelID,
CAST('=' + CAST(posCancelID AS VARCHAR(20)) + '=' AS VARCHAR(MAX)) AS IDs
FROM
( SELECT
Acc, TranType, posCancelID,
ROW_NUMBER() OVER (PARTITION BY Acc ORDER BY TranType, PosCancelID) AS rnk
FROM MCancel
) AS f
WHERE rnk = 1
UNION ALL
SELECT
Acc, TranType, posCancelID,
CAST(IDs + CAST(posCancelID AS VARCHAR(20)) + '=' AS VARCHAR(MAX))
FROM
( SELECT
m.*, r.IDs,
ROW_NUMBER() OVER (PARTITION BY m.Acc
ORDER BY m.TranType, m.PosCancelID) AS rn
FROM
rcte AS r
JOIN MCancel AS m
ON (m.Acc = r.Acc AND m.TranType > r.TranType)
WHERE
r.IDs NOT LIKE ('%=' + CAST(m.posCancelID AS VARCHAR(20)) + '=%')
) AS mc
WHERE rn = 1
)
SELECT Acc, TranType, posCancelID
FROM rcte
ORDER BY Acc, TranType ;
Run Code Online (Sandbox Code Playgroud)
两者都在dbfiddle.uk进行了测试
| 归档时间: |
|
| 查看次数: |
532 次 |
| 最近记录: |