Postgresql сгруппировать по нескольким строкам - PullRequest
0 голосов
/ 05 октября 2018

У меня есть эта таблица с именем hr_holidays_by_calendar.Я просто хочу отфильтровать строки, в которых у одного сотрудника есть два отпуска в один и тот же день .

Таблица hr_holidays_by_calendar:

enter image description here

Запрос, который я пробовал:
Не было рядомв решении этого.

select hol1.employee_id, hol1.leave_date, hol1.no_of_days, hol1.leave_state
from hr_holidays_by_calendar hol1
inner join
    (select employee_id, leave_date 
    from hr_holidays_by_calendar hol1
    group by employee_id, leave_date 
    having count(*)>1)sub
on hol1.employee_id=sub.employee_id and hol1.leave_date=sub.leave_date
where hol1.leave_state != 'refuse'
order by hol1.employee_id, hol1.leave_date

Ответы [ 4 ]

0 голосов
/ 05 октября 2018

Возвращает все строки, в которых существует дубликат :

SELECT employee_id, leave_date, no_of_days, leave_state
FROM   hr_holidays_by_calendar h
WHERE  EXISTS (
   SELECT                         -- select list can be empty for this
   FROM   hr_holidays_by_calendar
   WHERE  employee_id = h.employee_id
   AND    leave_date = h.leave_date
   AND    leave_state <> 'refuse'
   AND    ctid <> h.ctid
   )
AND    leave_state <> 'refuse'
ORDER  BY employee_id, leave_date;

Неясно, где следует применять leave_state <> 'refuse'.Вы должны были бы определить требования.Мой пример полностью игнорирует строки с leave_state = 'refuse'leave_state IS NULL с ним!).

ctid - это суррогат бедного человека для вашего необъявленного (неопределенного?) Первичного ключа.

:

0 голосов
/ 05 октября 2018

Я считаю, что простое использование GROUP BY может сделать всю работу за вас

select hol1.employee_id, hol1.leave_date, max(hol1.no_of_days)
from hr_holidays_by_calendar hol1
where hol1.leave_state != 'refuse'
group by hol1.employee_id, hol1.leave_date

Не ясно, что должно произойти, если две строки имеют разные no_of_days.

0 голосов
/ 05 октября 2018

Если вам нужны полные строки, один метод использует оконные функции:

select hc.*
from (select hc.*, count(*) over (partition by employee_id, leave_date) as cnt
      from hr_holidays_by_calendar hc
     ) hc
where cnt >= 2;

Агрегация подходит, если вам просто нужны идентификатор и даты сотрудника.

0 голосов
/ 05 октября 2018

Полагаю, вам просто нужно изменить свою логику.Вы можете использовать NOT EXISTS:

select h1.employee_id, h1.leave_date, h1.no_of_days, h1.leave_state
from hr_holidays_by_calendar h1
where 
  h1.leave_state <> 'refuse'
  and not exists (
    select 1
    from hr_holidays_by_calendar h2
    where 
      h1.employee_id = h2.employee_id
      and h1.leave_date = h2.leave_date
      group by employee_id, leave_date
      having count(*) > 1
  )

. Это приведет к сбросу каждой пары (сотрудник, дата), где у них более одной строки (уход в один и тот же день).

Я не принял во внимание количество дней, так как это кажется неправильным в любом случае - вы не можете получить отпуск дважды в один и тот же день, который длится разное количество дней.Если ваше приложение это позволяет, подумайте о применении дополнительной логики.Кроме того, вы не должны допускать попадания этих записей в таблицу: -)

...