今天带来的是pivot行转列的一个案例,根据工资查询抽象来的
首先是理解查询工资的表结构
1、首先工资是我们的工资,所以要有一个一个表
2、工资有许多部分组成,所以要有项目表
3、由上边两表即可再组合出新表项目工资表(一个人可以有多个工资项目)
4、最后就是工资表
既然表已经确定,接下来就是建表了
① --员工表(员工ID、工号、姓名、性别)
SELECT * INTO
#Employee
FROM (
SELECT 1 ID,100001 WorkCode,'张三' [Name],0 sex
UNION
SELECT 2,100002,'李四' ,0
UNION
SELECT 3,100003,'王五' ,0
UNION
SELECT 4,100004,'小明' ,0
UNION
SELECT 5,100005,'小红' ,1
UNION
SELECT 6,100006,'李华' ,1
) a
② --工资项目表(ID、名称)
–有社会工作经验的都知道,我们工资是有多部门组成的并不是单一的,也不是一层不变的,好比基本工资,这是不管如何都要发的,还有岗位工资,你是在这个岗位上的工资,
–公司有福利等,有餐补,住房补贴等,我们也有五险一金要交(虽然不是给公司,但是得从工资里扣)(刚踏足社会找工作的朋友记得留心,这是公司必须要给我们办理的,没有的话可以举报,…(苦口婆心800字省略))
SELECT * INTO
#SalaryElement
FROM (
SELECT 1 SalaryElementID,'基本工资' [SalaryItemName]
UNION
SELECT 2,'岗位工资'
UNION
SELECT 3,'餐补补贴'
UNION
SELECT 4,'宿舍费用'
UNION
SELECT 5,'固定绩效'
UNION
SELECT 6,'考核绩效'
UNION
SELECT 7,'平时加班'
UNION
SELECT 8,'周末加班'
UNION
SELECT 9,'五险一金'
UNION
SELECT 10,'其他类别'
) a
③ --项目工资表(ID、员工ID、项目ID、工资金额、工资表ID(表④的))
其实这里就已经算是可以查工资明细了,但是还有别的原因不能在这里查
讲解一条数据:员工ID为1的员工在工资项目为1的工资为1000元,他的工资表ID为1
这里SQL较长,但是数据有规律,有想法的小伙伴可以自己写个方法的出同样的效果
SELECT * INTO
#SalaryItem
FROM (
SELECT 1 ID,1 EmpID, 1 ElementID,1000 [Money],1 SalaryID
UNION
SELECT 2,1,2,1000,1 UNION
SELECT 3,1,3,1000,1 UNION
SELECT 4,1,4,1000,1 UNION
SELECT 5,1,5,1000,1 UNION
SELECT 6,1,6,1000,1 UNION
SELECT 7,1,7,1000,1 UNION
SELECT 8,1,8,1000,1 UNION
SELECT 9,1,9,1000,1 UNION
SELECT 10,1,10,1000,1 UNION
--李四
SELECT 11,2,1,2000,2 UNION
SELECT 12,2,2,2000,2 UNION
SELECT 13,2,3,2000,2 UNION
SELECT 14,2,4,2000,2 UNION
SELECT 15,2,5,2000,2 UNION
SELECT 16,2,6,2000,2 UNION
SELECT 17,2,7,2000,2 UNION
SELECT 18,2,8,2000,2 UNION
SELECT 19,2,9,2000,2 UNION
SELECT 20,2,10,2000,2 UNION
--王五
SELECT 11,3,1,3000,3 UNION
SELECT 22,3,2,3000,3 UNION
SELECT 23,3,3,3000,3 UNION
SELECT 24,3,4,3000,3 UNION
SELECT 25,3,5,3000,3 UNION
SELECT 26,3,6,3000,3 UNION
SELECT 27,3,7,3000,3 UNION
SELECT 28,3,8,3000,3 UNION
SELECT 29,3,9,3000,3 UNION
SELECT 30,3,10,3000,3 UNION
--小明
SELECT 31,4,1,4000,4 UNION
SELECT 32,4,2,4000,4 UNION
SELECT 33,4,3,4000,4 UNION
SELECT 34,4,4,4000,4 UNION
SELECT 35,4,5,4000,4 UNION
SELECT 36,4,6,4000,4 UNION
SELECT 37,4,7,4000,4 UNION
SELECT 38,4,8,4000,4 UNION
SELECT 39,4,9,4000,4 UNION
SELECT 40,4,10,4000,4 UNION
--小红
SELECT 41,5,1,5000,5 UNION
SELECT 42,5,2,5000,5 UNION
SELECT 43,5,3,5000,5 UNION
SELECT 44,5,4,5000,5 UNION
SELECT 45,5,5,5000,5 UNION
SELECT 46,5,6,5000,5 UNION
SELECT 47,5,7,5000,5 UNION
SELECT 48,5,8,5000,5 UNION
SELECT 49,5,9,5000,5 UNION
SELECT 50,5,10,5000,5 UNION
--李华
SELECT 51,6,1,6000,6 UNION
SELECT 52,6,2,6000,6 UNION
SELECT 53,6,3,6000,6 UNION
SELECT 54,6,4,6000,6 UNION
SELECT 55,6,5,6000,6 UNION
SELECT 56,6,6,6000,6 UNION
SELECT 57,6,7,6000,6 UNION
SELECT 58,6,8,6000,6 UNION
SELECT 59,6,9,6000,6 UNION
SELECT 60,6,10,6000,6
) a
④–工资表(ID、员工ID、年月)
上边表③说了,那里就可以查询了,但是需要表④,也就是年月的原因,那把年月加到表③不就行了么?是这样么,真正工资表数据并不是我这里这么简单还有其他字段,我只是抽出主要的
SELECT * INTO
#Salary
FROM (
SELECT 1 ID,1 EmpID,'2020-07' Years
UNION
SELECT 2,2,'2020-07'
UNION
SELECT 3,3,'2020-07'
UNION
SELECT 4,4,'2020-07'
UNION
SELECT 5,5,'2020-07'
UNION
SELECT 6,6,'2020-07'
)a
- 现在表已经建好并添加了测试数据了,那就进行真经事了
- 关联数据表
select *
from #Salary x
left join #Employee e on e.ID =x.EmpID
left join #SalaryItem Item on Item.SalaryID =x.ID
left join #SalaryElement element on element.SalaryElementID = Item.ElementID
查询结果呢就是下图了
这里我们可以清楚的看到一个人对各项目的金额
--现在的数据还是以每个工资项目为一列显示的,对于我们的工资条来说,这还不是最后的结果
--那现在我们要做的就是列转行
--使用pivot for
--先列出我们要查的工资项
这里为了代码的美观,我使用参数进行处理查询的列
declare @ItemPivot nvarchar(max)
declare @ItemPivotShow nvarchar(max)
set @ItemPivot = ''--pivot内对接的
set @ItemPivotShow = '' --最终显示的
SET @ItemPivot='
[基本工资],[岗位工资],[餐补补贴],[宿舍费用],[考核绩效],
[固定绩效],[平时加班],[周末加班],[五险一金],[其他类别]
';
SET @ItemPivotShow='
isnull([基本工资],0) [基本工资],
isnull([岗位工资],0) [岗位工资],
isnull([餐补补贴],0) [餐补补贴],
isnull([宿舍费用],0) [宿舍费用],
isnull([考核绩效]+[固定绩效],0) [绩效],
isnull([平时加班]+[周末加班],0) [加班],
isnull([五险一金],0) [五险一金],
isnull([其他类别],0) [其他]
,isnull([基本工资] + [岗位工资] + [餐补补贴] + [宿舍费用] + [考核绩效] + [固定绩效] + [平时加班] + [周末加班] - [五险一金] - [其他类别],0) [应发金额]
--,isnull([基本工资] + [岗位工资] + [餐补补贴] + [宿舍费用] + [考核绩效] + [固定绩效] + [平时加班] + [周末加班] - [五险一金] - [其他类别],0) [实发金额]
然后呢,就是筛选条件了(像我们查一个人的工资,某个月的工资)
declare @years nvarchar(max) --这个可做存储过程的参数用
set @years ='2020-07'
--还可加姓名、工号等(只限制于这里)
declare @pWhere nvarchar(max)
set @pWhere = ''
set @pWhere = 'x.Years=''' + @years + ''''
最后就到主角pivot登场了
declare @SalaryShow nvarchar(max)
set @SalaryShow = '
select ID,Years,WorkCode,Name, ' + @ItemPivotShow + '
from (
select x.ID,x.Years,e.WorkCode,e.Name,Money,SalaryItemName
from #Salary x
left join #Employee e on e.ID =x.EmpID
left join #SalaryItem Item on Item.SalaryID =x.ID
left join #SalaryElement element on element.SalaryElementID = Item.ElementID
where ' + @pWhere + '
) t pivot (max(Money) for SalaryItemName in (' + @ItemPivot + ')) s
'
--pivot 聚合函数(int等类型的字段) for 要显示的列的字段 in (需要用的字段)
最后就是执行了
EXEC (@SalaryShow
+'
DROP TABLE #Employee
DROP TABLE #SalaryElement
DROP TABLE #SalaryItem
DROP TABLE #Salary
'
)
最后:关于对这类的讲解、优化及拓展
- 对于上边添加临时表的SQL,大家可以把他存入字段中,类似这里的@SalaryShow参数一样,然后再最后的EXEC内相加与@SalaryShow之前即可
- 因为我们需要缴税,所以上边的应发工资还不一定是实际我们到手的工资,所以,我们还可以加个扣税处理,进行扣税管理,得出实发工资(后边有空我再看下吧…)
- 我们建立SalaryItem表是因为要可维护的原因,所以单独做了一个表,工资的组成有很多,不同地方也有不同的工资项目,好比宿舍费用,有的公司不提供宿舍,也没有宿舍补贴之类的
- 实际上的工资计算是没有我这里所描述的这么简单,因为没一个工资项的工资已经得出来了,在实际中,我们要多方面取值
(像考勤,有迟到早退的,加班得申请并通过才有效,加班了有与打卡考勤有关,是否是有效加班呢,加班工资又安什么规则计算呢,不同公司不同部门又不一样,还有考核…)
…(再次省略不知道多少字,半瓶水,也不能全理解工资方面的,我只是一个菜鸟码农) - 这段SQL也可以做成存储过程,参数可以是年月、工号、姓名,有意拓展的话可以再把员工表分细点,加上公司部门岗位,然后查
这就是pivot行转列实践:真实工资查询的全部内容了。谢谢阅读!
追加:https://download.csdn.net/download/qq_44471040/12674013
这是我整理上传上去的的SQL脚本,有能力的小伙伴可以下载支持下!