当排名函数不够时,排除 select 中的记录

Excluding records in select when rank functions is not enough

我被困在 select 查询中以从 table 中获得最佳匹配,如下所示:

Name A B TotalA TotalB
Name1 10 1 10 1
Name2 15 2 25 3
Name3 20 3 45 6
Name4 25 4 70 10
Name5 30 5 100 15
Name6 35 6 135 21
Name7 51 7 175 28
..... .... ...... ...... ......
..... .... ...... ...... ......

我试图找到 B 总和最低的最佳 6 条记录,但还有一个附加条件,即 A 总和需要高于 150。

这个table按B排序,最好的结果在最前面。因此,6 个最佳结果中 B 的总和为 21,但在这种情况下,A 的总和为 135,低于 150。因此应排除记录 nb 6,并应包括下一个 nb 7。所以最好的结果是记录1-5和记录7中B的总和=22,而A的总和是151,这就足够了。

我使用带分区和顺序的排名函数,但每次查询都返回 0 条记录。是否有可能排除第 6 条记录并将结果取 7,因此 A 的总和将 > 150?

这似乎是 knapsack problem 的一个变体,它是 NP-Complete,最简单的(编码)解决方案就是强制执行每个排列。

鉴于你有固定数量的项目,你可以通过自加入来做到这一点

SELECT TOP (1)
  *
FROM Items i1
JOIN Items i2 ON i2.Name > i1.Name
JOIN Items i3 ON i3.Name > i2.Name
JOIN Items i4 ON i4.Name > i3.Name
JOIN Items i5 ON i5.Name > i4.Name
JOIN Items i6 ON i6.Name > i5.Name
CROSS APPLY (VALUES (
    i1.A + i2.A + i3.A + i4.A + i5.A + i6.A,
    i1.B + i2.B + i3.B + i4.B + i5.B + i6.B
)) v(TotalA, TotalB)
WHERE TotalA > 150
ORDER BY
  TotalB;

Name in this case is just a proxy for some unique column

db<>fiddle

可能有更有效的解决方案,具体取决于您的具体问题。