从表中选择顶部X,其中SUM(列)< = @variable

时间:2011-10-17 14:23:06

标签: sql sql-server

我正在尝试选择前n行,其中列的总和小于或等于我作为变量传入的数字。

TableX的:

Col1  Col2
1     10
2     10
3     5
4     20

所以基本上我正在尝试做这样的事情:

SELECT * FROM TableX WHERE SUM(Col2) <= 25

我期待结果:

Col1  Col2
1     10
2     10
3     5

4 个答案:

答案 0 :(得分:3)

您正在寻找HAVING条款。

不幸的是,我此时无法访问sql server来测试一个完整的解决方案,但是...在mysql中这似乎完全符合你的要求,如果我有T-SQL也应该这样做我没弄错。

SELECT A.Col1, A.Col2, SUM(B.Col2) AS CumulativeCol2
FROM TableX A
INNER JOIN TableX B ON B.Col1 <= A.Col1
GROUP BY A.Col1
HAVING SUM(B.Col2) <= 25

返回:

Col1    Col2    CumulativeCol2
1       10      10
2       10      20
3       5       25

答案 1 :(得分:2)

declare @table as table(Col1 int, Col2 int)
insert into @table values (1, 10)
insert into @table values (2, 10)
insert into @table values (3, 5)
insert into @table values (4, 20)



 ;with TableWithIndex(Row, Col1, Col2)
 as
 (
   select row_number() over(order by Col1) Row, Col1, Col2
   from @table   
 ),
 ColTable(Row, Col1, Col2, Col2Sum)
 as (
   select Row, Col1, Col2, Col2 Col2Sum
   from TableWithIndex
   where Row = 1 and Col2 <= 25
   union all
   select ti.Row, ti.Col1, ti.Col2, ti.Col2 + Col2Sum
   from TableWithIndex ti
   inner join ColTable ct on ct.Row + 1 = ti.Row   
   where ti.Col2 + Col2Sum <= 25
 )
 select Col1, Col2
 from ColTable
 option (maxrecursion 0)

答案 2 :(得分:1)

这是您需要的(包括概念证明):

declare @t table(Col1 int, Col2 int)

insert into @t values
(1, 10),
(2, 10),
(3, 5),
(4, 20),
(5, 3)

select * from
(
    select t1.Col1, t1.Col2, SUM(t2.Col2) as runningtotal
    from @t t1
    inner join @t t2 on t1.Col1 >= t2.Col1
    group by t1.Col1, t1.Col2
) ss
where runningtotal <= 25

答案 3 :(得分:0)

修改:请勿将TestDataID identity(1,1)列中的值与RowNumber值混淆。这些值之间没有联系。

此解决方案使用递归CTE:

CREATE TABLE TestData
(
     TestDataID INT IDENTITY(2,2) PRIMARY KEY
    ,ProductID  INT NOT NULL
    ,SalesQty   INT NOT NULL
);

INSERT  TestData 
SELECT  1, 10
UNION ALL
SELECT  1, 10
UNION ALL
SELECT  1, 5
UNION ALL
SELECT  1, 11

UNION ALL
SELECT  2, 20
UNION ALL
SELECT  2, 2
UNION ALL
SELECT  2, 10

UNION ALL
SELECT  3, 27
UNION ALL
SELECT  3, 3;

DECLARE @param INT = 25;

CREATE TABLE #Results --or table variable
(
     TestDataID INT NOT NULL
    ,ProductID  INT NOT NULL
    ,SalesQty   INT NOT NULL
    ,RowNumber  INT NOT NULL
    ,PRIMARY KEY(RowNumber, ProductID)
);
INSERT  #Results(TestDataID, ProductID, SalesQty, RowNumber)
SELECT  a.TestDataID, a.ProductID, a.SalesQty,
        ROW_NUMBER() OVER(PARTITION BY a.ProductID ORDER BY a.TestDataID) RowNumber
FROM    TestData a;

;WITH CteRecursive
AS
(
    SELECT   a.ProductID
            ,a.RowNumber
            ,a.TestDataID
            ,a.SalesQty
            ,a.SalesQty AS RunningTotal
    FROM    #Results a
    WHERE   a.RowNumber = 1
    AND     a.SalesQty <= @param
    UNION ALL
    SELECT   crt.ProductID
            ,crt.RowNumber
            ,crt.TestDataID
            ,crt.SalesQty 
            ,prev.RunningTotal + crt.SalesQty
    FROM    #Results crt
    INNER JOIN CteRecursive prev ON prev.ProductID = crt.ProductID
    AND     prev.RowNumber + 1 = crt.RowNumber
    WHERE   prev.RunningTotal + crt.SalesQty <= @param
)
SELECT   a.TestDataID
        ,a.ProductID
        ,a.SalesQty

        ,a.RunningTotal
FROM    CteRecursive a
ORDER BY a.ProductID, a.RowNumber;

DROP TABLE #Results;
DROP TABLE TestData;

结果:

TestDataID  ProductID   SalesQty    RunningTotal
----------- ----------- ----------- ------------
2           1           10          10
4           1           10          20
6           1           5           25
10          2           20          20
12          2           2           22