найти праздники для людей, работающих в некоторых отраслях - PullRequest
1 голос
/ 23 апреля 2019

У меня есть 3 таблицы данных: некоторые люди работают в филиале, а другие работают в 2 или более филиалах.

Мы определяем 2 случая выходного: тип 1 для всех ветвей Закрыт, а тип 0 для некоторых ветвей Закрыт (не все).

Теперь я хочу найти человека, как в отпуске, если все люди-ветки закрыты

Праздник

ID  Date           AllBranch
1   2019/02/01     1
2   2019/02/05     0
3   2019/02/06     0

BranchHoliday

ID  HolidayID       BranchID
1   2               2
2   2               3
3   3               2

PersonBranch

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, поэтому:

  • PersonID-10 работает только в BranchId 2, определяется в таблице BranchHoliday, поэтому находится в праздничном
  • PersonID-11 работает в 2 филиалах (2,3) и все 2,3 определены как закрытые в таблице BranchHoliday, поэтому находятся в выходных
  • PersonID-12 работает в 2 филиалах (2,4) и BranchId 4 НЕ определяется как закрытый в BranchHoliday, поэтому НЕ работает в выходные дни

В дате (2019/02/06) AllBranch равно 0 так:

  • PersonID-10 работает только в BranchId 2, а ветвь 2 определяется в таблице BranchHoliday, поэтому находится в отпуске
  • PersonID-11 работает в 2 ветви (2,3), и только ветвь 3 НЕ определена как закрытая в таблице BranchHoliday, поэтому она находится в НЕ праздничном
  • PersonID-12 работает в ветке 2 (2,4) и ветке 3 НЕ определяется как закрытый в таблице BranchHoliday, поэтому НЕ в выходной

Мне нужен SQL-запрос, и я использую SQL Server 2016

Ответы [ 2 ]

2 голосов
/ 23 апреля 2019

Я не знаю, почему вы приняли ответ Эстебана, учитывая, что ваш ожидаемый результат таков. Только 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

И все же запрос Эстебана выдает 7 строк. В праздник 6 февраля неправильно включается лицо № 11, которому разрешено иметь выходной 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

Предположительно, выходные лица человека должны быть проверены (объединены) по таблице праздничных дней, верно? Но запрос Эстебана не делает этого.

Запрос Эстебана дает неправильный вывод:

Тест в реальном времени: 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

BranchHoliday

ID  HolidayID       BranchID
1   2               2
2   2               3
3   3               2
4   4               2
5   4               4

Запрос Эстебана снова дает неправильный вывод:

Тест в реальном времени: 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 |

И учитывая эти данные. Обратите внимание, что только 2 человека в филиале № 5 могут иметь выходной 2 апреля.

Праздник

ID  Date           AllBranch
1   2019/02/01     1
2   2019/02/05     0
3   2019/02/06     0
4   2019/04/02     0

BranchHoliday

ID  HolidayID       BranchID
1   2               2
2   2               3
3   3               2
4   4               5

Запрос Эстебана снова приводит к неправильным выводам, поскольку только 2 человека из филиала № 5 могут иметь выходной 2 апреля. Тем не менее, его запрос включает лиц, которые не должны иметь выходных 2 апреля. № 11 не включены в ветку № 5, их не должно быть 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 |

Это должно произвести это. Ни одному сотруднику не разрешается иметь выходной 2 апреля, даже человеку № 10 не разрешается иметь выходной 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 |

Это правильный запрос (версия Postgres):

Тест в реальном времени: 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 |

Версия SQL Server:

Тест в реальном времени: 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 |
2 голосов
/ 23 апреля 2019

Одним из решений было бы разбить его на две части:

Сначала выбираются люди для праздников 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...