如何在内部/联合查询中排除某些行
How to exclude some rows on inner / union queries
我的 SQL 查询有问题(我知道我不擅长这个任务 :( )
使用 SLQ Server 2014,我有一个 table 存储包含日期名称和日期时间的银行工作日。
另一方面,有一个 table 的技术人员参与了一个项目。他们可以正常工作,甚至可以在银行工作日工作。
我收到一个查询,以便生成工资单,让所有那些工作过的技术人员获取技术代码、姓名、项目 ID 和日期,但我需要为所有未工作的技术人员获取另一个列表 (UNION)在银行假日期间,因为它们也需要包含在工资单报告中(银行假日也支付,但需要区分)。
我尝试使用连接获取该列表,该列表应包含技术代码、名称、项目 ID 和来自 Holidays 的日期,如果他们那天没有工作(该信息被检索在第一个查询中,因为存储在 Sessions table 中。唯一具有两个 table 共同点的值是日期。
到目前为止,我会向您提供我的查询:
-- To get real work hours / days within date range
select
distinct s.TechnicianCode, t.Name, s.JobProjectId as jobId,
s.SignInDate as [date], 'w'
from
JobSession s
inner join
Technician t on t.TechnicianCode = s.TechnicianCode
inner join
JobAssignedTech jt on jt.TechCode = s.TechnicianCode
left join
LeaveDate ld on ld.TechnicianCode = s.TechnicianCode
where
(cast(s.SignInDate as date) >= cast(@DateFrom as date)
and cast(s.SignInDate as date) <= cast(@DateTo as date))
and jt.IsActive = 1
假期包含:
HolidayID HolidayDate Name.....
3 2015-08-19 00:00:00.000 August Bank Holiday ...
5 2015-08-20 00:00:00.000 August Bank Holiday ...
例如,对于这样的查询
select
distinct s.TechnicianCode, t.Name, s.JobProjectId, s.SignInDate
from
JobSession s
inner join
Technician t on s.TechnicianCode = t.TechnicianCode
where
cast(s.SignInDate as date) between cast('2015/08/17' as date) and cast('2015/08/24' as date)
我明白了
TechnicianCode Name JobProjectId SignInDate
282 Patrick Flood TEST JOB CHQ E2443 2015-08-17
332 Anthony Farrell TEST JOB CHQ E2443 2015-08-17
342 Ciaran Kimmage TEST JOB CHQ E2443 2015-08-17
343 Anthony Clinton TEST JOB CHQ E2443 2015-08-17
440 Darragh Byrne TEST JOB CHQ E2443 2015-08-17
440 Darragh Byrne TEST JOB CHQ E2443 2015-08-20
489 Thomas Cunningham TEST JOB CHQ E2443 2015-08-17
491 Aidan Lee TEST JOB CHQ E2443 2015-08-17
497 Brian Canavan TEST JOB CHQ E2443 2015-08-17
TE Test Sandyford site 07.15 2015-08-17
所以我需要得到一份显示这些技术人员的列表,但日期应该是银行假期日期,并且前提是他们在那些日子里没有工作,因此,例如,代码为 440 的技术人员不得在列表中出现两次因为他在 8 月 20 日工作,它应该是这样的:
TechnicianCode Name JobProjectId SignInDate
282 Patrick Flood TEST JOB CHQ E2443 2015-08-19
282 Patrick Flood TEST JOB CHQ E2443 2015-08-20
332 Anthony Farrell TEST JOB CHQ E2443 2015-08-19
332 Anthony Farrell TEST JOB CHQ E2443 2015-08-20
342 Ciaran Kimmage TEST JOB CHQ E2443 2015-08-19
342 Ciaran Kimmage TEST JOB CHQ E2443 2015-08-20
343 Anthony Clinton TEST JOB CHQ E2443 2015-08-19
343 Anthony Clinton TEST JOB CHQ E2443 2015-08-20
440 Darragh Byrne TEST JOB CHQ E2443 2015-08-19
489 Thomas Cunningham TEST JOB CHQ E2443 2015-08-19
489 Thomas Cunningham TEST JOB CHQ E2443 2015-08-20
491 Aidan Lee TEST JOB CHQ E2443 2015-08-19
491 Aidan Lee TEST JOB CHQ E2443 2015-08-20
497 Brian Canavan TEST JOB CHQ E2443 2015-08-19
497 Brian Canavan TEST JOB CHQ E2443 2015-08-19
TE Test Sandyford site 07.15 2015-08-19
TE Test Sandyford site 07.15 2015-08-20
我已经尝试过使用 UNION、SUB QUERIES、EXIST、IN、INNER 等等,但我什么也没得到:-/
稍有帮助将不胜感激
您可以在 UNION
语句中执行此操作,该语句将所有技术人员连接到范围内的所有假期,然后使用 LEFT JOIN
查找在假期工作的技术人员,然后进行过滤如果他们这样做了。
见下文:
select distinct
s.TechnicianCode,
t.Name,
s.JobProjectId,
s.SignInDate
from
JobSession s
inner join
Technician t on s.TechnicianCode = t.TechnicianCode
where
cast(s.SignInDate as date) between cast('2015/08/17' as date) and cast('2015/08/24' as date)
UNION
SELECT
t.TehnicianCode,
t.Name,
NULL AS JobProjectID,
h.HolidayDate
FROM
Technician t
INNER JOIN
Holidays h ON
h.HolidayDate BETWEEN cast('2015/08/17' as date) and cast('2015/08/24' as date) -- connect every technician to every holiday in the range
LEFT JOIN
JobSession s ON -- check for technicians who worked on the holiday
t.TechnicianCode = s.TechnicianCode AND
cast(s.SignInDate as date) = h.HolidayDate
WHERE s.TechnicianCode IS NULL -- filter out the technicans who worked on the holiday
好吧,我终于找到了解决方案(对于稍微了解 SQL 的人来说并不难,但对于像我这样的新手来说是一个很好的解决方案。
为了只获得在银行假期期间没有工作的技术人员,我不得不在 UNION 的第二部分使用 "NOT EXISTS":
select distinct(s.TechnicianCode), t.Name, jt.JobProjectId as jobId, cast(h.HolidayDate as date) as date, 'h'---this is to know if tech has worked or was on holidays
from Holidays h, JobSession s
inner join Technician t on s.TechnicianCode = t.TechnicianCode
inner join JobAssignedTech jt on jt.TechCode = t.TechnicianCode
where cast(h.HolidayDate as date) between cast(@DateFrom as date) and cast(@DateTo as date)
and cast(s.SignInDate as date) between cast(@DateFrom as date) and cast(@DateTo as date)
and jt.IsActive = 1
and not exists (
Select *--, JobProjectId, SignInDate , h.HolidayDate, h.Name
from JobSession s1
where cast(s1.SignInDate as date) between cast(@DateFrom as date) and cast(@DateTo as date)
and s1.TechnicianCode = s.TechnicianCode and cast(s1.SignIndate as date) = cast(h.HolidayDate as date)
)
我的 SQL 查询有问题(我知道我不擅长这个任务 :( )
使用 SLQ Server 2014,我有一个 table 存储包含日期名称和日期时间的银行工作日。
另一方面,有一个 table 的技术人员参与了一个项目。他们可以正常工作,甚至可以在银行工作日工作。
我收到一个查询,以便生成工资单,让所有那些工作过的技术人员获取技术代码、姓名、项目 ID 和日期,但我需要为所有未工作的技术人员获取另一个列表 (UNION)在银行假日期间,因为它们也需要包含在工资单报告中(银行假日也支付,但需要区分)。
我尝试使用连接获取该列表,该列表应包含技术代码、名称、项目 ID 和来自 Holidays 的日期,如果他们那天没有工作(该信息被检索在第一个查询中,因为存储在 Sessions table 中。唯一具有两个 table 共同点的值是日期。
到目前为止,我会向您提供我的查询:
-- To get real work hours / days within date range
select
distinct s.TechnicianCode, t.Name, s.JobProjectId as jobId,
s.SignInDate as [date], 'w'
from
JobSession s
inner join
Technician t on t.TechnicianCode = s.TechnicianCode
inner join
JobAssignedTech jt on jt.TechCode = s.TechnicianCode
left join
LeaveDate ld on ld.TechnicianCode = s.TechnicianCode
where
(cast(s.SignInDate as date) >= cast(@DateFrom as date)
and cast(s.SignInDate as date) <= cast(@DateTo as date))
and jt.IsActive = 1
假期包含:
HolidayID HolidayDate Name.....
3 2015-08-19 00:00:00.000 August Bank Holiday ...
5 2015-08-20 00:00:00.000 August Bank Holiday ...
例如,对于这样的查询
select
distinct s.TechnicianCode, t.Name, s.JobProjectId, s.SignInDate
from
JobSession s
inner join
Technician t on s.TechnicianCode = t.TechnicianCode
where
cast(s.SignInDate as date) between cast('2015/08/17' as date) and cast('2015/08/24' as date)
我明白了
TechnicianCode Name JobProjectId SignInDate
282 Patrick Flood TEST JOB CHQ E2443 2015-08-17
332 Anthony Farrell TEST JOB CHQ E2443 2015-08-17
342 Ciaran Kimmage TEST JOB CHQ E2443 2015-08-17
343 Anthony Clinton TEST JOB CHQ E2443 2015-08-17
440 Darragh Byrne TEST JOB CHQ E2443 2015-08-17
440 Darragh Byrne TEST JOB CHQ E2443 2015-08-20
489 Thomas Cunningham TEST JOB CHQ E2443 2015-08-17
491 Aidan Lee TEST JOB CHQ E2443 2015-08-17
497 Brian Canavan TEST JOB CHQ E2443 2015-08-17
TE Test Sandyford site 07.15 2015-08-17
所以我需要得到一份显示这些技术人员的列表,但日期应该是银行假期日期,并且前提是他们在那些日子里没有工作,因此,例如,代码为 440 的技术人员不得在列表中出现两次因为他在 8 月 20 日工作,它应该是这样的:
TechnicianCode Name JobProjectId SignInDate
282 Patrick Flood TEST JOB CHQ E2443 2015-08-19
282 Patrick Flood TEST JOB CHQ E2443 2015-08-20
332 Anthony Farrell TEST JOB CHQ E2443 2015-08-19
332 Anthony Farrell TEST JOB CHQ E2443 2015-08-20
342 Ciaran Kimmage TEST JOB CHQ E2443 2015-08-19
342 Ciaran Kimmage TEST JOB CHQ E2443 2015-08-20
343 Anthony Clinton TEST JOB CHQ E2443 2015-08-19
343 Anthony Clinton TEST JOB CHQ E2443 2015-08-20
440 Darragh Byrne TEST JOB CHQ E2443 2015-08-19
489 Thomas Cunningham TEST JOB CHQ E2443 2015-08-19
489 Thomas Cunningham TEST JOB CHQ E2443 2015-08-20
491 Aidan Lee TEST JOB CHQ E2443 2015-08-19
491 Aidan Lee TEST JOB CHQ E2443 2015-08-20
497 Brian Canavan TEST JOB CHQ E2443 2015-08-19
497 Brian Canavan TEST JOB CHQ E2443 2015-08-19
TE Test Sandyford site 07.15 2015-08-19
TE Test Sandyford site 07.15 2015-08-20
我已经尝试过使用 UNION、SUB QUERIES、EXIST、IN、INNER 等等,但我什么也没得到:-/
稍有帮助将不胜感激
您可以在 UNION
语句中执行此操作,该语句将所有技术人员连接到范围内的所有假期,然后使用 LEFT JOIN
查找在假期工作的技术人员,然后进行过滤如果他们这样做了。
见下文:
select distinct
s.TechnicianCode,
t.Name,
s.JobProjectId,
s.SignInDate
from
JobSession s
inner join
Technician t on s.TechnicianCode = t.TechnicianCode
where
cast(s.SignInDate as date) between cast('2015/08/17' as date) and cast('2015/08/24' as date)
UNION
SELECT
t.TehnicianCode,
t.Name,
NULL AS JobProjectID,
h.HolidayDate
FROM
Technician t
INNER JOIN
Holidays h ON
h.HolidayDate BETWEEN cast('2015/08/17' as date) and cast('2015/08/24' as date) -- connect every technician to every holiday in the range
LEFT JOIN
JobSession s ON -- check for technicians who worked on the holiday
t.TechnicianCode = s.TechnicianCode AND
cast(s.SignInDate as date) = h.HolidayDate
WHERE s.TechnicianCode IS NULL -- filter out the technicans who worked on the holiday
好吧,我终于找到了解决方案(对于稍微了解 SQL 的人来说并不难,但对于像我这样的新手来说是一个很好的解决方案。
为了只获得在银行假期期间没有工作的技术人员,我不得不在 UNION 的第二部分使用 "NOT EXISTS":
select distinct(s.TechnicianCode), t.Name, jt.JobProjectId as jobId, cast(h.HolidayDate as date) as date, 'h'---this is to know if tech has worked or was on holidays
from Holidays h, JobSession s
inner join Technician t on s.TechnicianCode = t.TechnicianCode
inner join JobAssignedTech jt on jt.TechCode = t.TechnicianCode
where cast(h.HolidayDate as date) between cast(@DateFrom as date) and cast(@DateTo as date)
and cast(s.SignInDate as date) between cast(@DateFrom as date) and cast(@DateTo as date)
and jt.IsActive = 1
and not exists (
Select *--, JobProjectId, SignInDate , h.HolidayDate, h.Name
from JobSession s1
where cast(s1.SignInDate as date) between cast(@DateFrom as date) and cast(@DateTo as date)
and s1.TechnicianCode = s.TechnicianCode and cast(s1.SignIndate as date) = cast(h.HolidayDate as date)
)