在SQL Server中将数量分配给多行

时间:2017-09-04 17:22:37

标签: sql-server sql-server-2014

我有任意金额花费,比方说1000美元

我还有几十行,让我们说员工的薪水作为专栏

我如何按照优先顺序在员工中分配1000美元的预算,这样他们每个人都可以获得工资栏中的价值,直到钱全部用完为止?一旦预算全部用完,剩下的员工就会留下零。

Employee, Rank, Salary
John, 1, 500$
Anne, 2, 400$
Rob, 3, 300$
Bill, 4, 200$

结果应为:

John, 1, 500$, 500$
Anne, 2, 400$, 400$
Rob, 3, 300$, 100$    --Only 100 left in the budget
Bill, 4, 200$, 0$

知道如何在没有光标的情况下进行操作吗?

3 个答案:

答案 0 :(得分:3)

这是一种方式。

CREATE TABLE #emp (Employee VARCHAR(10), Rank INT, Salary INT CHECK (Salary > 0));

INSERT INTO #emp
VALUES      ('John',1,500),
            ('Anne',2,400),
            ('Rob',3,300 ),
            ('Bill',4,200);

DECLARE @Budget INT = 1000;

WITH T1 AS
( SELECT  * ,
          running_total = SUM(Salary) OVER (ORDER BY Rank 
                                            ROWS BETWEEN UNBOUNDED PRECEDING 
                                            AND CURRENT ROW)
         FROM #emp ), 
T2 AS 
(
SELECT *, 
      prev_running_total = LAG(running_total) OVER (ORDER BY Rank)
FROM T1
)
SELECT   Employee,
         Rank,
         Salary,
         CASE
             --run out
             WHEN prev_running_total >= @Budget THEN 0
             --budget left but not enough for whole salary
             WHEN running_total > @Budget THEN @Budget - prev_running_total 
             --Can do full amount 
             ELSE Salary
         END
FROM     T2;

DROP TABLE #emp 

答案 1 :(得分:0)

如果预算低于薪水

 CASE
             --run out
             WHEN prev_running_total >= @Budget THEN 0
             WHEN @Budget <= T2.Salary  THEN @Budget  
             --budget left but not enough for whole salary
             WHEN running_total > @Budget THEN @Budget - prev_running_total 
             --Can do full amount 
             ELSE Salary
         END

答案 2 :(得分:0)

   -- FOR EARLIER VERSIONS OF SQL SERVER (CTE SUPPORTED)

   DECLARE @Budget INT = 905;

   IF OBJECT_ID ('TEMPDB..#emp') IS NOT NULL
   DROP TABLE #EMP

   CREATE TABLE #emp (Employee VARCHAR(10), Rank INT, Salary INT CHECK (Salary > 0));

   INSERT INTO #emp
   VALUES      ('John',1,500),
               ('Anne',2,400),
               ('Rob',3,300 ),
               ('Bill',4,200);

   WITH T1 AS
   ( SELECT  A.* ,
             running_total = SUM(B.Salary) -- OVER (ORDER BY [Rank] )
                                               --ROWS BETWEEN UNBOUNDED PRECEDING 
                                               --AND CURRENT ROW
                                            --)
            FROM #emp A
            LEFT JOIN #emp B ON B.[Rank] <= A.[Rank]
            GROUP BY A.Employee, A.[Rank], A.Salary
            --ORDER BY 1,2
    )

   , 
   T2 AS 
   (
    SELECT A.*, prev_running_total = B.running_total
    FROM T1 A 
    LEFT JOIN T1 B ON B.[Rank] + 1 = A.[Rank]

   )

   SELECT   Employee,
            Rank,
            Salary,
            CASE
                --run out
                WHEN isnull(prev_running_total,0) >= @Budget THEN 0
                --budget left but not enough for whole salary
                WHEN running_total > @Budget THEN @Budget - isnull(prev_running_total, 0)
                --Can do full amount 
                ELSE Salary
            END Distribution 

   FROM     T2
   ORDER BY 2;

   IF OBJECT_ID ('TEMPDB..#emp') IS NOT NULL
   DROP TABLE #EMP