使用设置表按比例分配奖金分配

时间:2016-12-27 06:13:46

标签: sql split sql-server-2012 aggregate-functions outer-join

CREATE TABLE #empInfo(emp_id INT, dept_id INT, salary INT)
CREATE TABLE #empBonus(dep_id INT, emp_id INT, bonus INT) 

我在EmployeeBonus上面有两个表,我会在每年为奖金表中的员工分配奖金,但是例如我们只会这样做一年这样的年份列没有给出。

INSERT INTO #empInfo VALUES 
(111, 100, 5000),
(112, 100, 4000),
(113, 100, 4000),
(114, 100, 3500),
(115, 100, 4500),
(116, 100, 3000),
(114, 200, 3500),
(115, 200, 4500),
(116, 200, 3000),
(114, 300, 3500),
(115, 300, 3500),
(116, 300, 3500)

INSERT INTO #empBonus VALUES 
(100, 111, 1000),
(100, NULL, 4000),
(100, 111, 500),
(100, NULL, 4000),
(100, 113, 700),
(200, 114, 600),
(200, NULL, 1600),
(300, 116, 900)

上面,如果在empBonus表中定义了员工ID,则应该为该员工分配奖金,如果为空,则表示奖励未列入empBonus的所有员工,并且将根据他们的工资。

我们可以为多个员工定义奖金,对于同一个员工可以是多个,在这种情况下,我们必须总计总奖金并相应地执行操作。同样的情况是NULL。

例如,根据下面给出的公式,我在EXCEL进行了以下计算,以便于理解,SQL我正在尝试使用OUTER APPLY,但没有得到我想要的单一查询?

--Formula = bonus*salary/totSalary(of respective group or employee)
DeptID  EmpID   TotBonus    Salary      TotSalary   Bonus
100     111     1500        5000        5000        1500.00000000000
100     112     8000        4000        15000       2133.33333333333
100     113     700         4000        4000        700.00000000000
100     114     8000        3500        15000       1866.66666666666
100     115     8000        4500        15000       2400.00000000000
100     116     8000        3000        15000       1600.00000000000
200     114     600         3500        3500        600.00000000000
200     115     1600        4500        7500        960.00000000000
200     116     1600        3000        7500        640.00000000000
300     114     0           3500        7000        0.00000000000
300     115     0           3500        7000        0.00000000000
300     116     900         3500        3500        900.00000000000

任何帮助将不胜感激,提前感谢:)

2 个答案:

答案 0 :(得分:1)

嗯,这对我来说是一个很好的挑战。

首先,创建一个cte来计算TotSalary列:

;With cteTotalSalary as
(
    -- select total salary for employees that are in the bonus table
    SELECT e.emp_id, dept_id, Salary, Salary As TotSalary
    FROM #empInfo e
    INNER JOIN #empBonus b ON e.dept_id = b.dep_id AND e.emp_id = b.emp_id 

    UNION

    -- select total salary for employees that are in NOT the bonus table
    SELECT e.emp_id, dept_id, Salary, SUM(Salary) OVER(PARTITION BY dept_id) As TotSalary
    FROM #empInfo e
    WHERE EXISTS (
        SELECT 1
        FROM #empBonus b 
        WHERE e.dept_id = b.dep_id 
        AND b.emp_id IS NULL
    )
    AND NOT EXISTS
    (
        SELECT 1
        FROM #empBonus b 
        WHERE e.dept_id = b.dep_id 
        AND e.emp_id = b.emp_id
    )
)

然后,用工会两次查询此cte以获得两种类型的奖金(员工奖金和部门奖金)

-- Get the bonus of the employess that exists in the empBonus table
SELECT c.emp_id, dept_id, SUM(Bonus) OVER(PARTITION BY c.emp_id) as Bonus, Salary, TotSalary, CAST(SUM(CAST(Bonus as decimal)) OVER(PARTITION BY c.emp_id) as decimal) as [Bonus Distribution]
FROM cteTotalSalary c
INNER JOIN #empBonus b ON c.dept_id = b.dep_id AND c.emp_id = b.emp_id

UNION

-- Get the bonus of the employees that does not exists in the empBonus table
SELECT c.emp_id, dept_id, SUM(Bonus) OVER(PARTITION BY c.emp_id), Salary, TotSalary, SUM(CAST(Bonus as decimal) * Salary / TotSalary) OVER(PARTITION BY c.emp_id)
FROM cteTotalSalary c
INNER JOIN #empBonus b ON c.dept_id = b.dep_id AND b.emp_id IS NULL
AND NOT EXISTS (
        SELECT 1
        FROM #empBonus b 
        WHERE c.dept_id = b.dep_id 
        AND c.emp_id = b.emp_id
)

结果:

emp_id  dept_id Bonus   Salary  TotSalary   Bonus Distribution
111     100     1500    5000    5000        1500.000000000
112     100     8000    4000    19000       1684.210526314
113     100     8000    4000    19000       1684.210526314
114     100     8000    3500    19000       1473.684210526
115     100     8000    4500    19000       1894.736842104
116     100     8000    3000    19000       1263.157894736

您可以在行动here

中看到它

答案 1 :(得分:1)

以下是使用FULL OUTER JOINSUM() OVER()窗口聚合

的一种方法
;WITH cte
     AS (SELECT ei.emp_id,ei.dept_id, eb.dep_id,
                bonus = COALESCE(bonus, Max(CASE WHEN eb.emp_id IS NULL THEN bonus END)
                                          OVER( partition BY COALESCE(ei.dept_id, eb.dep_id) )),
                salary = Cast(salary AS NUMERIC(22, 6)),
                TotSalary= Iif(eb.emp_id IS NULL, Sum(CASE WHEN eb.emp_id IS NULL THEN salary END)
                                                    OVER(partition by ei.dept_id), salary)
         FROM   #empInfo ei
                FULL OUTER JOIN (SELECT bonus= Sum(bonus),
                                        dep_id,
                                        emp_id
                                 FROM   #empBonus
                                 GROUP  BY dep_id,
                                           emp_id) eb
                             ON ei.dept_id = eb.dep_id
                                AND eb.emp_id = ei.emp_id)
SELECT emp_id,
       bonus,
       salary,
       TotSalary,
       ( bonus * salary ) / NULLIF(TotSalary, 0)
FROM   cte
WHERE  emp_id IS NOT NULL 

<强>结果:

+--------+-------+-------------+-----------+--------------------+
| emp_id | bonus |   salary    | TotSalary | Bonus Distribution |
+--------+-------+-------------+-----------+--------------------+
|    111 |  1500 | 5000.000000 |      5000 | 1500.00000000000   |
|    112 |  8000 | 4000.000000 |     19000 | 1684.21052631578   |
|    113 |  8000 | 4000.000000 |     19000 | 1684.21052631578   |
|    114 |  8000 | 3500.000000 |     19000 | 1473.68421052631   |
|    115 |  8000 | 4500.000000 |     19000 | 1894.73684210526   |
|    116 |  8000 | 3000.000000 |     19000 | 1263.15789473684   |
+--------+-------+-------------+-----------+--------------------+