我有Table A
,其中包含以下数据:
Id Value
1 100
2 63
4 50
6 24
7 446
我想选择带SUM(value) <= 200
的第一行。
所以期望的输出应该是:
Id Value
1 100
4 50
6 24
答案 0 :(得分:8)
简单回答
您需要找到每行的累积总和,并且由于您需要尽可能多的行,因此您需要从最低值(ORDER BY Value
)开始:
WITH Data AS
( SELECT Id,
Value,
CumulativeValue = SUM(Value) OVER(ORDER BY Value, Id)
--FROM (VALUES (1, 100), (2, 300), (4, 50), (6, 24), (7, 446)) AS t (Id, Value)
FROM TableA AS t
)
SELECT d.Id, d.Value
FROM Data AS d
WHERE d.CumulativeValue <= 200
ORDER BY d.Id;
完整答案
如果您希望更有选择性地选择总和少于200的行,那么在新的示例数据中会更复杂一些:
Id Value
1 100
2 63
4 50
6 24
7 446
有3种不同的组合允许总共少于200:
Id Value
1 100
2 63
6 24
--> 187
Id Value
2 63
4 50
6 24
--> 137
Id Value
1 100
4 50
6 24
--> 174
执行此操作的唯一方法是获取总和小于200的所有组合,然后选择所需的组合,为此,您需要使用递归公用表表达式来获取所有组合:
WITH TableA AS
( SELECT Id, Value
FROM (VALUES (1, 100), (2, 63), (4, 50), (6, 24), (7, 446)) t (Id, Value)
), CTE AS
( SELECT Id,
IdList = CAST(Id AS VARCHAR(MAX)),
CumulativeValue = Value,
ValueCount = 1
FROM TableA AS t
UNION ALL
SELECT T.ID,
IdList = CTE.IDList + ',' + CAST(t.ID AS VARCHAR(MAX)),
CumulativeValue = CTE.CumulativeValue + T.Value,
ValueCount = CTE.ValueCount + 1
FROM CTE
INNER JOIN TableA AS T
ON ',' + CTE.IDList + ',' NOT LIKE '%,' + CAST(t.ID AS VARCHAR(MAX)) + ',%'
AND CTE.ID < T.ID
WHERE T.Value + CTE.CumulativeValue <= 200
)
SELECT *
FROM CTE
ORDER BY ValueCount DESC, CumulativeValue DESC;
此输出(删除单行)
Id IdList CumulativeValue ValueCount
-------------------------------------
6 1,2,6 187 3
6 1,4,6 174 3
6 2,4,6 137 3
2 1,2 163 2
4 1,4 150 2
6 1,6 124 2
4 2,4 113 2
6 2,6 87 2
6 4,6 74 2
因此,您需要选择最符合您要求的行组合,例如,如果您需要,如前所述,尽可能接近200的最大行数,那么您需要选择顶部结果,如果你想要最低总数,那么你需要改变排序。
然后,您可以使用EXISTS
获取原始输出,以获取IdList
中存在的记录:
WITH TableA AS
( SELECT Id, Value
FROM (VALUES (1, 100), (2, 63), (4, 50), (6, 24), (7, 446)) t (Id, Value)
), CTE AS
( SELECT Id,
IdList = CAST(Id AS VARCHAR(MAX)),
CumulativeValue = Value,
ValueCount = 1
FROM TableA AS t
UNION ALL
SELECT T.ID,
IdList = CTE.IDList + ',' + CAST(t.ID AS VARCHAR(MAX)),
CumulativeValue = CTE.CumulativeValue + T.Value,
ValueCount = CTE.ValueCount + 1
FROM CTE
INNER JOIN TableA AS T
ON ',' + CTE.IDList + ',' NOT LIKE '%,' + CAST(t.ID AS VARCHAR(MAX)) + ',%'
AND CTE.ID < T.ID
WHERE T.Value + CTE.CumulativeValue <= 200
), Top1 AS
( SELECT TOP 1 IdList, CumulativeValue
FROM CTE
ORDER BY ValueCount DESC, CumulativeValue DESC -- CHANGE TO MEET YOUR NEEDS
)
SELECT *
FROM TableA AS t
WHERE EXISTS
( SELECT 1
FROM Top1
WHERE ',' + Top1.IDList + ',' LIKE '%,' + CAST(t.ID AS VARCHAR(MAX)) + ',%'
);
这不是很有效,但我目前看不到更好的方法。
返回
Id Value
1 100
2 63
6 24
这是最接近200的最可能的行。由于有多种方法可以实现总和小于200&#34;的行数,因此还有多种编写查询的方法。您需要更加具体地了解您的组合偏好,以便获得所需的确切答案。
答案 1 :(得分:4)
这应返回预期结果:
WITH TableWithTotals AS
(SELECT
id,
value,
SUM (Value) OVER (ORDER BY Value, Id) as total
FROM myTable)
SELECT * FROM TableWithTotals
WHERE total <=200;
此代码将最大化满足200限制的记录数,因为计算的运行总数超过了有序值。
答案 2 :(得分:1)
根据我的理解你的要求,我认为以下查询应该对你有所帮助。
WITH FinalResult AS
(SELECT
id,
value,
SUM (Value) OVER (ORDER BY Value, Id) as ValueCount
FROM TableA)
SELECT * FROM FinalResult
WHERE ValueCount <=200;
答案 3 :(得分:-1)
你应该试试这个: -
SELECT Id, Value FROM TableName WHERE Value <=200