我有3个数据表:有些人在一个分支中工作,而另一些人在2个或更多分支中工作。
我们定义了2个例假:类型1的所有分支都已关闭,类型0的某个分支已关闭(不是全部)。
现在我想找人,如果所有人都关闭了,假期怎么样?
ID Date AllBranch
1 2019/02/01 1
2 2019/02/05 0
3 2019/02/06 0
ID HolidayID BranchID
1 2 2
2 2 3
3 3 2
ID PersonID BranchID
1 10 2
2 11 2
3 11 3
4 12 2
5 12 4
我想要的结果是:
PersonID Hdate
10 2019/02/01
11 2019/02/01
12 2019/02/01
10 2019/02/05
11 2019/02/05
10 2019/02/06
在日期(2019/02/01)中,AllBranch是1,所以所有人都在度假
在日期(2019/02/05)中,AllBranch为0,因此:
在日期(2019/02/06)中,AllBranch为0,因此:
我需要SQL查询,并且正在使用SQL Server 2016
答案 0 :(得分:2)
一种解决方案是将其分为两部分:
首先选择AllBranch假期的人员,然后再选择特定假期的人员,在这些假期中,他们所工作的所有分支机构均具有确定的假期:
SELECT AllPers.PersonID, H.Date
FROM Holiday H
INNER JOIN (
SELECT DISTINCT PersonID
FROM PersonBranch
) AllPers ON H.AllBranch = 1
UNION
SELECT Sub.PersonID, H.Date
FROM Holiday H
INNER JOIN (
SELECT PB.PersonID
, SUM(IIF(BH.BranchID IS NULL, 1, 0)) AS AnyBranchOpen
FROM PersonBranch PB
LEFT JOIN BranchHoliday BH ON PB.BranchID = BH.BranchID
GROUP BY PB.PersonID
) Sub ON AnyBranchOpen = 0
WHERE H.AllBranch = 0
答案 1 :(得分:2)
鉴于您的预期结果是这样,我不知道您为什么接受Esteban的回答。仅6行。
PersonID Hdate
10 2019/02/01
11 2019/02/01
12 2019/02/01
10 2019/02/05
11 2019/02/05
10 2019/02/06
但是Esteban的查询产生7行。在2月6日的假期中,错误地将11号人员包括在2月6日的假期中。这与您的问题定义相矛盾:
In date (2019/02/06) AllBranch is 0 so:
* ...
* PersonID-11 work in 2 branch(2,3) and only branch 3 is NOT define closed
in BranchHoliday table so is in NOT holiday
大概应该在假期表中检查(加入)人员的BranchHoliday,对吗?但是Esteban的查询没有这样做。
Esteban的查询产生不正确的输出:
实时测试:http://sqlfiddle.com/#!18/86728/2
| PersonID | Date |
|----------|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 10 | 2019-02-06 |
| 11 | 2019-02-06 |
给出这些不同的数据:
ID Date AllBranch
1 2019/02/01 1
2 2019/02/05 0
3 2019/02/06 0
4 2019/04/02 0
ID HolidayID BranchID
1 2 2
2 2 3
3 3 2
4 4 2
5 4 4
Esteban的查询再次产生不正确的输出:
实时测试:http://sqlfiddle.com/#!18/10348/1
| PersonID | Date |
|----------|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 12 | 2019-02-05 |
| 10 | 2019-02-06 |
| 11 | 2019-02-06 |
| 12 | 2019-02-06 |
| 10 | 2019-04-02 |
| 11 | 2019-04-02 |
| 12 | 2019-04-02 |
它应该产生这个:
实时测试:http://sqlfiddle.com/#!17/7b6be/1
| id | date |
|----|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 10 | 2019-02-06 |
| 10 | 2019-04-02 |
| 12 | 2019-04-02 |
并给出这些数据。请注意,只有#5分支机构的人员才可以在4月2日放假。
ID Date AllBranch
1 2019/02/01 1
2 2019/02/05 0
3 2019/02/06 0
4 2019/04/02 0
ID HolidayID BranchID
1 2 2
2 2 3
3 3 2
4 4 5
Esteban的查询再次产生不正确的输出,因为只允许分支#5上的人员在4月2日放假。但是,他的查询中包括不应被允许在4月2日上假期的人。#10和#11未包含在分支#5中,因此不应在4月2日出现。
实时测试:http://sqlfiddle.com/#!18/fd1d3/1
| PersonID | Date |
|----------|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 10 | 2019-02-06 |
| 11 | 2019-02-06 |
| 10 | 2019-04-02 |
| 11 | 2019-04-02 |
它应该产生这个。不允许任何员工在4月2日放假,甚至10号员工也不允许在4月2日放假,因为10号员工仅在#2分支机构。只有#5分支机构的人员可以放假。
实时测试:http://sqlfiddle.com/#!17/299f73/1
| id | date |
|----|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 10 | 2019-02-06 |
实时测试:http://sqlfiddle.com/#!17/6cf97/2
select h.date, p.id
from holiday h
cross join person p
join personbranch pb
on p.id = pb.personid
left join branchholiday bh
on h.id = bh.holidayid and pb.branchid = bh.branchid
group by h.date, p.id
having
every(h.allbranch)
or
-- choose only every person whose branch ids are all present in branchholiday
-- filtered by holidayid from holiday.id
every(bh.branchid is not null)
order by h.date, p.id
输出与问题定义的预期输出匹配:
| id | date |
|----|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 10 | 2019-02-06 |
实时测试:http://sqlfiddle.com/#!18/41a54/3
select p.id, h.date
from holiday h
cross join person p
join personbranch pb
on p.id = pb.personid
left join branchholiday bh
on h.id = bh.holidayid and pb.branchid = bh.branchid
group by h.date, p.id
having
count(case when h.allbranch = 1 then 1 end) = count(*)
or
-- choose only every person whose branch ids are all present in branchholiday
-- filtered by holidayid from holiday.id
count(case when bh.branchid is not null then 1 end) = count(*)
order by h.date, p.id
输出与问题定义的预期输出匹配:
| id | date |
|----|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 10 | 2019-02-06 |
这是另一个SQL Server的every
习惯用法。您可以将count(condition) = count(*)
更改为min
的方法:
实时测试:http://sqlfiddle.com/#!18/41a54/4
having
min(case when h.allbranch = 1 then 1 else 0 end) = 1
or
-- choose only every person whose branch ids are all present in branchholiday
-- filtered by holidayid from holiday.id
min(case when bh.branchid is not null then 1 else 0 end) = 1
输出与问题定义的预期输出匹配:
| id | date |
|----|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 10 | 2019-02-06 |