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
分组,这与dept1114115116
中相同,它是将值与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 |
+--------+-------+-------------+-----------+--------------------+