我有一张表出席和一个活动类型表
我想每月将每个人的活动分组在不同的栏目中
示例表:
人员ID
日期
GateIn
GateOut
ActivityID
ID
名称
值为Activity.Name为:Present,Absence,Ill和Holiday
是PersonID
月
年
没有
假日
生病
LessThan4Hours
MoreThan4Hours
MoreThan5Hours
创建此分组的最佳方法是什么? 我已经有两个SQL语句,但两者似乎都太不友好了
谁能帮助我? 感谢
SELECT year(att.Date) as cYear, month(att.Date) as cMonth, att.PersonID, COUNT(1) as Absence, 0 as Holiday, 0 as Ill, 0 as LessThan4Hours, 0 as MoreThan4Hours, 0 as MoreThan5Hours
FROM Attendance att
inner join Activities act on att.ActivityID = act.ID
WHERE act.Name = 'Absence'
GROUP BY year(att.Date), month(att.Date), att.PersonID
UNION
SELECT year(att.Date) as cYear, month(att.Date) as cMonth, att.PersonID, 0 as Absence, COUNT(1) as Holiday, 0 as Ill, 0 as LessThan4Hours, 0 as MoreThan4Hours, 0 as MoreThan5Hours
FROM Attendance att
inner join Activities act on att.ActivityID = act.ID
WHERE act.Name = 'Holiday'
GROUP BY year(att.Date), month(att.Date), att.PersonID
UNION
SELECT year(att.Date) as cYear, month(att.Date) as cMonth, att.PersonID, 0 as Absence, 0 as Holiday, count(1) as Ill, 0 as LessThan4Hours, 0 as MoreThan4Hours, 0 as MoreThan5Hours
FROM Attendance att
inner join Activities act on att.ActivityID = act.ID
WHERE act.Name = 'Ill'
GROUP BY year(att.Date), month(att.Date), att.PersonID
UNION
SELECT year(att.Date) as cYear, month(att.Date) as cMonth, att.PersonID, 0 as Absence, 0 as Holiday, 0 as Ill, COUNT(1) as LessThan4Hours, 0 as MoreThan4Hours, 0 as MoreThan5Hours
FROM Attendance att
inner join Activities act on att.ActivityID = act.ID
WHERE att.GateOut is not null
AND (DATEDIFF(n, att.GateIn, att.GateOut)/60) <= 4
AND act.Name = 'Present'
GROUP BY year(att.Date), month(att.Date), att.PersonID
UNION
SELECT year(att.Date) as cYear, month(att.Date) as cMonth, att.PersonID, 0 as Absence, 0 as Holiday, 0 as Ill, 0 as LessThan4Hours, COUNT(1) as MoreThan4Hours, 0 as MoreThan5Hours
FROM Attendance att
inner join Activities act on att.ActivityID = act.ID
WHERE att.GateOut is not null
AND (DATEDIFF(n, att.GateIn, att.GateOut)/60) > 4
AND (DATEDIFF(n, att.GateIn, att.GateOut)/60) <= 5
AND act.Name = 'Present'
GROUP BY year(att.Date), month(att.Date), att.PersonID
UNION
SELECT year(att.Date) as cYear, month(att.Date) as cMonth, att.PersonID, 0 as Absence, 0 as Holiday, 0 as Ill, 0 as LessThan4Hours, 0 as MoreThan4Hours, COUNT(1) as MoreThan5Hours
FROM Attendance att
inner join Activities act on att.ActivityID = act.ID
WHERE att.GateOut is not null
AND (DATEDIFF(n, att.GateIn, att.GateOut)/60) > 5
AND act.Name = 'Present'
GROUP BY year(att.Date), month(att.Date), att.PersonID
我也在SELECT CASE中解决了这个问题,可能还会更糟?
SELECT a.PersonID, a.cYear, a.cMonth, SUM(a.Absence) AS Absence, SUM(a.Holiday) AS Holiday, SUM(a.Ill) AS Ill, SUM(a.LessThan4Hours) AS LessThan4Hours, SUM(a.MoreThan4Hours) AS MoreThan4Hours, SUM(a.MoreThan5Hours) AS MoreThan5Hours
FROM
(
SELECT year(att.Date) as cYear, month(att.Date) as cMonth, att.PersonID, CASE
WHEN act.Name = 'Ill' THEN 1
WHEN act.Name = 'Holiday' THEN 0
WHEN act.Name = 'Absence' THEN 0
WHEN GateOut = null THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) > 5 THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) > 4 THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) <= 4 THEN 0
ELSE 0
END AS Ill,
CASE
WHEN act.Name = 'Ill' THEN 0
WHEN act.Name = 'Holiday' THEN 1
WHEN act.Name = 'Absence' THEN 0
WHEN GateOut = null THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) > 5 THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) > 4 THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) <= 4 THEN 0
ELSE 0
END AS Holiday,
CASE
WHEN act.Name = 'Ill' THEN 0
WHEN act.Name = 'Holiday' THEN 0
WHEN act.Name = 'Absence' THEN 1
WHEN GateOut = null THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) > 5 THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) > 4 THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) <= 4 THEN 0
ELSE 0
END AS Absence,
CASE
WHEN act.Name = 'Ill' THEN 0
WHEN act.Name = 'Holiday' THEN 0
WHEN act.Name = 'Absence' THEN 0
WHEN GateOut = null THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) > 5 THEN 1
WHEN (DATEDIFF(n, gatein, gateout)/60) > 4 THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) <= 4 THEN 0
ELSE 0
END AS MoreThan5Hours,
CASE
WHEN act.Name = 'Ill' THEN 0
WHEN act.Name = 'Holiday' THEN 0
WHEN act.Name = 'Absence' THEN 0
WHEN GateOut = null THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) > 5 THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) > 4 THEN 1
WHEN (DATEDIFF(n, gatein, gateout)/60) <= 4 THEN 0
ELSE 0
END AS MoreThan4Hours,
CASE
WHEN act.Name = 'Ill' THEN 0
WHEN act.Name = 'Holiday' THEN 0
WHEN act.Name = 'Absence' THEN 0
WHEN GateOut = null THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) > 5 THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) > 4 THEN 0
WHEN (DATEDIFF(n, gatein, gateout)/60) <= 4 THEN 1
ELSE 0
END AS LessThan4Hours
from Attendance att
inner join Activities act on att.ActivityID = act.ID
) a
GROUP BY a.PersonID, a.cYear, a.cMonth
ORDER BY a.cYear DESC, a.cMonth DESC, a.PersonID
答案 0 :(得分:1)
这可能更容易阅读和遵循。内部“PreChk”查询遍历记录,只是将它们标记为不同的类型和小时,然后应用按您的要求分组的摘要。
SELECT
PreChk.PersonID,
PreChk.cYear,
PreChk.cMonth,
SUM(PreChk.Absence) AS Absence,
SUM(PreChk.Holiday) AS Holiday,
SUM(PreChk.Ill) AS Ill,
SUM( case when PreChk.HrsDif > 5 then 1 else 0 end ) as MoreThan5Hours,
SUM( case when PreChk.HrsDif > 4 AND PreChk.HrsDif < 5 then 1 else 0 end ) as MoreThan4Hours,
SUM( case when PreChk.HrsDif < 4 then 1 else 0 end ) as LessThan4Hours
from
( SELECT
att.PersonID,
year(att.Date) as cYear,
month(att.Date) as cMonth,
CASE WHEN act.Name = 'Ill' THEN 1 else 0 end as Ill,
CASE WHEN act.Name = 'Holiday' THEN 1 else 0 end as Holiday,
CASE WHEN act.Name = 'Absence' THEN 1 else 0 end as Absence,
CASE when GateOut = null
THEN 0
ELSE DATEDIFF(n, gatein, gateout)/60) end as HrsDif
from
Attendance att
inner join Activities act
on att.ActivityID = act.ID ) PreChk
GROUP BY
PreChk.PersonID,
PreChk.cYear,
PreChk.cMonth
ORDER BY
PreChk.cYear DESC,
PreChk.cMonth DESC,
PreChk.PersonID
答案 1 :(得分:0)
这是显示此方法的sqlfiddle
select personid,
datepart(month, date) as Month,
datepart(year, date) as year,
case when [present] is not null then 1 else 0 end as present,
case when [absence] is not null then 1 else 0 end as absence,
case when [III] is not null then 1 else 0 end as III,
case when [holiday] is not null then 1 else 0 end as holiday,
sum(case when datediff(hour, gatein, gateout) <= 4 then 1 else 0 end) as LessThan4Hours,
sum(case when datediff(hour, gatein, gateout) > 4 and datediff(hour, gatein, gateout) <= 5 then 1 else 0 end) as GreaterThan4Hours,
sum(case when datediff(hour, gatein, gateout) > 5 then 1 else 0 end) as GreaterThan5Hours
from
(
select a.*, act.name
from attendance a
join activity act on a.activityid = act.activityid
) as source
pivot
(
max(name)
FOR name in ([present],[absence],[III],[holiday])
) as p
group by personid,
datepart(month, date),
datepart(year, date),
case when [present] is not null then 1 else 0 end,
case when [absence] is not null then 1 else 0 end,
case when [III] is not null then 1 else 0 end,
case when [holiday] is not null then 1 else 0 end