简单的答案
您需要找到每一行的累积和,并且由于您想要尽可能多的行,因此您需要从最小值开始 (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 的行数。由于有多种方法可以实现“x 个总和小于 200 的行数”,因此编写查询的方法也有多种。您需要更具体地了解您的组合偏好,以便获得所需的确切答案。