我正在尝试创建一个查询,在给定的日期范围内告诉我某人是否缺席。到目前为止,我有两个查询,一个用于获取每个人和日期,如果他们被安排在,一个如果你通过它,那个人的卡代码告诉你他们在时钟上刷了多少次在终端中,一些滑动> 0会告诉我他们是否在。
以下是获取每个人的第一个查询以及他们应该参加的日期。
SELECT
CHINA_VISION_PubCards.CardNo,
CHINA_VISION_PubPersonnel.Name,
LEFT(CONVERT(DATE, ATDScheduling.ScheduleDate), 11) AS Date1
FROM CHINA_VISION_PubPersonnel
INNER JOIN
CHINA_VISION_DorEvents ON CHINA_VISION_PubPersonnel.Reference = CHINA_VISION_DorEvents.Reference
INNER JOIN
CHINA_VISION_PubCards ON CHINA_VISION_PubPersonnel.Reference = CHINA_VISION_PubCards.PubPersonnel_Ref
RIGHT OUTER JOIN
ATDScheduling ON CHINA_VISION_PubPersonnel.Reference = ATDScheduling.PubPersonnel_Ref
WHERE
(ATDScheduling.ScheduleDate BETWEEN '2015-02-12' AND '2015-02-22') AND (CHINA_VISION_PubPersonnel.Name <> 'null') AND
(ATDScheduling.ATDShift_Ref > 1)
ORDER BY CHINA_VISION_PubPersonnel.Name
此查询产生如下结果:
ClockNo | Name | Date should be in
5726 Person 1 2015-02-14
5726 Person 1 2015-02-15
5726 Person 1 2015-02-21
5726 Person 1 2015-02-22
5728 Person 2 2015-02-13
5728 Person 2 2015-02-14
5728 Person 2 2015-02-15
5728 Person 2 2015-02-20
5728 Person 2 2015-02-21
5728 Person 2 2015-02-22
5736 Person 3 2015-02-12
5736 Person 3 2015-02-13
5736 Person 3 2015-02-14
这是第二个查询以及传递卡片代码和日期时的结果。
SELECT COUNT(*) AS Count
FROM CHINA_VISION_DorEvents
INNER JOIN
CHINA_VISION_PubCards ON CHINA_VISION_DorEvents.CardCode = CHINA_VISION_PubCards.CardCode
WHERE (CHINA_VISION_DorEvents.EventTM BETWEEN CONVERT(DATETIME, '2015-02-12 00:00:00', 102) AND CONVERT(DATETIME,102)) AND
(CHINA_VISION_DorEvents.DorCtrls_Ref = '16')
GROUP BY CHINA_VISION_PubCards.CardNo
HAVING (CHINA_VISION_PubCards.CardNo = '5726')
这个查询会有这样的输出:
Count
4
如果计数高于0,那么他们就会在时钟机器上刷卡,表明它们已经进入。他们刷卡的数量并不重要,只要它高于0
所以对于缺席,如果计数为0,则它们不存在,并且应该将计数器增加一个
如果可能的话,我希望查询的内容看起来像是一起组合的
Clock Number | Name | Absence count
5725 person 1 3
5728 person 2 0
等等。
答案 0 :(得分:2)
我喜欢CTE的可读性,并且使用NOT EXISTS和OUTER APPLY因为它通常更快,但是至少有4或5种不同的方式来编写这个查询。这是一个展示如何获得缺席的例子。我还删除了一些不需要的代码并简化了查询。更多评论内联:
/*
Since staff are always on the schedule (otherwise how could they be absent?),
and we need their cards for the next query, let's do all INNER joins here.
We get one row per staffer, per day.
*/
With ScheduleCTE AS (
SELECT
c.CardNo,
p.Name,
s.ScheduleDate
FROM
ATDScheduling s
INNER JOIN CHINA_VISION_PubPersonnel p ON p.Reference = s.PubPersonnel_Ref
INNER JOIN CHINA_VISION_PubCards c ON p.Reference = c.PubPersonnel_Ref
WHERE
s.ScheduleDate BETWEEN '2015-02-12' AND '2015-02-22'
AND s.ATDShift_Ref > 1
)
/*
not sure if your EventTM field includes time, so I'm trimming the time off both date fields to be safe.
This slows the query, so avoid the type conversion if not necessary!
*/
SELECT
s.CardNo,
s.Name,
COUNT(*) AS AbsentCount
FROM
ScheduleCTE s
WHERE
NOT EXISTS (
--if staffer was present, let's remove him from the result
SELECT TOP 1 1
FROM
CHINA_VISION_DorEvents e
WHERE
e.CardCode = s.CardCode
AND CAST(FLOOR(CAST(s.Date1 AS FLOAT)) AS DATETIME) = CAST(FLOOR(CAST(e.EventTM AS FLOAT)) AS DATETIME)
)
GROUP BY
s.CardNo,
s.Name
ORDER BY s.Name
;
答案 1 :(得分:1)
这是一个WITH语句示例。未经测试,因为我不能100%确定您的查询是如何工作的,而且我很快就完成了。基本上使用WITH在ORDER BY CHINA_VISION_PubPersonnel.Name之后的第二个SELECT语句中查询Clocks_CTE;在WITH之前需要
Kahn可能有更好的想法,但也许这是一个开始。
--This is the first query which is stored in Clocks_CTE
;WITH Clocks_CTE
(SELECT CHINA_VISION_PubCards.CardNo AS [ClockNum],
CHINA_VISION_PubPersonnel.Name AS [Name],
LEFT(CONVERT(DATE, ATDScheduling.ScheduleDate), 11) AS [Date1]
FROM CHINA_VISION_PubPersonnel
INNER JOIN
CHINA_VISION_DorEvents ON CHINA_VISION_PubPersonnel.Reference = CHINA_VISION_DorEvents.Reference
INNER JOIN
CHINA_VISION_PubCards ON CHINA_VISION_PubPersonnel.Reference = CHINA_VISION_PubCards.PubPersonnel_Ref
RIGHT OUTER JOIN
ATDScheduling ON CHINA_VISION_PubPersonnel.Reference = ATDScheduling.PubPersonnel_Ref
WHERE (ATDScheduling.ScheduleDate BETWEEN '2015-02-12'
AND '2015-02-22')
AND (CHINA_VISION_PubPersonnel.Name <> 'null')
AND (ATDScheduling.ATDShift_Ref > 1)
ORDER BY CHINA_VISION_PubPersonnel.Name)
-- End Clocks_CTE
-- You can now do a query on Clocks_CTE
-- Basic example query that you would need to modify
SELECT Count(ClockNum) AS [AbsenceCount],
c.Name,
c.ClockNum
FROM Clocks_CTE c
INNER JOIN CHINA_VISION_DorEvents.CardCode ON c.ClockNum
WHERE (c.Date1 BETWEEN CONVERT(DATETIME, '2015-02-12 00:00:00', 102) AND CONVERT(DATETIME,102))
AND (CHINA_VISION_DorEvents.DorCtrls_Ref = '16')
GROUP BY c.ClockNum
c.Name
ORDER BY c.ClockNum