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

Sql 使用设置表按比例分配奖金,sql,split,sql-server-2012,aggregate-functions,outer-join,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) 如上所述,如果员工id在empBonus表中定义,则奖金应分配给该员工,如果为空,则表示所有未在empBonus中列出且将根据其工资获得奖金的

我有上面两个表,分别是
员工
奖金
,我每年都会在奖金表中为员工分配奖金,但在示例中,我们只会分配一年,因此不会给出年份列

CREATE TABLE #empInfo(emp_id INT, dept_id INT, salary INT)
CREATE TABLE #empBonus(dep_id INT, emp_id INT, bonus INT) 
如上所述,如果员工id在
empBonus
表中定义,则奖金应分配给该员工,如果为空,则表示所有未在
empBonus
中列出且将根据其工资获得奖金的员工的奖金

我们可以为多个员工定义奖金,也可以为同一员工定义多个奖金,在这种情况下,我们必须将奖金总额相加,并相应地执行操作。NULL的大小写相同

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

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)

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

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

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

--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
然后,向工会查询此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
)

您可以在操作中看到它

这里有一种方法使用
完全外部联接
SUM()OVER()
窗口聚合

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
结果:

;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 

您是如何获得
totalsalary
的?奖金是为
111
员工定义的,因此
111
的总工资是
5000
的,而其他人的合并奖金是定义的,因此总工资将是所有这些员工工资的总和。i、 e.
19000
在上述示例中。我们也可以采用另一种方法。您能分享一下您在excel中完成的奖金分配公式吗?我对
excel
不太熟悉,所以我在那方面是手工完成的。我们不能在
SQL
中实现上述要求吗?您的查询已经过测试,对于我当前的场景+1来说确实有效,但正如我在
中所说的那样,BONUS
表记录可以是多个或重复的,在这种情况下,我们必须
求和
值并相应地分配。如果我加上(100111500),(100null,4000),你能相应地更新吗?它应该在所有人中分配8000,并且应该分配1500到111。谢谢,@Prdp它从各个方面都工作得很好,我会在几次测试后很快回来:)它也满足了我当前的要求(+1),但我发现它有点长,我们能否在@Prdp answer中解决上述评论中提到的多值方案。我看到Prdp已经更新了他的答案来解决这个问题,您还需要更新我的答案吗?很荣幸,先生,这对大家都有帮助。对不起,当我添加另一个带有'200'代码和
empid
的部门时,它并没有将数据
dept
分组,这与dept1
114115116
中相同,它是将值与
dept1
的员工相加<代码>(200114600),(200,NULL,1600)很抱歉,我想不出你可能想到的每一个场景。这是你第一次问问题的责任。如果您的样本数据和期望的输出能够涵盖更多的案例,那么您可能会得到更好的答案。很难从你的评论中得出预期的结果。如果你想编辑这个问题以包含所有这些新信息,那么也许我可以编辑我的答案来涵盖它。
;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   |
+--------+-------+-------------+-----------+--------------------+