Как получить ближайшее значение к параметру запроса в SQL?

У меня есть таблица (shop_staff_relationvm), которая сохраняет отношения между персоналом и магазином.

Он имеет 3 столбца: id_shop, id_staff и change_date.

  • id_staff => внешний ключ персонала
  • id_shop => внешний ключ магазина
  • change_date ==> всякий раз, когда создается новое отношение персонала к магазину, я сохраняю дату настройки (магазин персонала может меняться несколько раз)

3 столбца выше представляют встраиваемый первичный ключ для таблицы shop_staff_relationvm.

В запросе у меня есть 2 параметра запроса: idShop и дата.

Я пытаюсь получить список сотрудников, принадлежащих определенному магазину (idShop) в определенном месяце (requestMonth).

Поэтому мне нужно получить список сотрудников, когда requestMonth находится между первой датой отношений между персоналом и магазином и последней датой отношений.

Вот пример:

STAFF     | SHOP     | CHANGE DATE
----------+----------+-------------
Staff A   | Shop 1   | 10-01-2019
Staff A   | Shop 2   | 10-03-2019
Staff A   | Shop 3   | 10-05-2019

Предполагая, что у нас есть requestMonth = 02-2019

Тогда: в магазине 1 будет персонал А, в магазине 2 не будет персонала, а в магазине 3 не будет персонала.

Предполагая, что у нас есть requestMonth = 03-2019

Тогда: в магазине 1 не будет персонала, в магазине 2 будет персонал А, а в магазине 3 не будет персонала.

Предполагая, что у нас есть requestMonth = 06-2019

Тогда: в магазине 1 не будет персонала, в магазине 2 не будет персонала, а в магазине 3 будет персонал А.

Вот формула, которую я придумал:

first date of relation <= requestMonth <= first date of next relation

У меня нет проблем с получением первой даты отношения, но у меня есть проблема с получением первой даты следующего отношения (которое я пришел к выводу, что это следующее ближайшее значение к первой дате отношения).

PS: я использую собственный запрос JPA

Я попытался использовать order by (change_date - first date of relation), чтобы получить первое ближайшее значение к первой дате отношения. но это всегда давало мне максимальное значение (в приведенном выше примере я всегда получал 05-2019 месяц)

Я также пытался использовать LEAD, чтобы получить следующее ближайшее значение. Однако, используя приведенный выше пример:

For requestMonth = 02-2019 : the LEAD was equal to 03-2019 => correct

For requestMonth = 03-2019 : the LEAD was equal to 01-2019 => wrong => It should be 05-2019

Это весь запрос:

SELECT s.* FROM staffvm s INNER JOIN shop_staff_relationvm ss ON ss.id_staff = s.id_staff WHERE ss.id_shop = 2 and 
(CASE WHEN ((SELECT MAX(to_date(to_char(ss.change_date, 'yyyy-MM'), 'yyyy-MM')) FROM shop_staff_relationvm ss WHERE ss.id_staff = s.id_staff) > to_date('2019-02-16', 'yyyy-MM') 
and (SELECT MIN(to_date(to_char(ss.change_date, 'yyyy-MM'), 'yyyy-MM')) FROM shop_staff_relationvm ss WHERE ss.id_staff = s.id_staff) <= to_date('2019-02-16', 'yyyy-MM') ) 
THEN 
((SELECT ((LEAD (to_date(to_char(ss.change_date, 'yyyy-MM'), 'yyyy-MM')) OVER (ORDER BY ss.id_staff DESC)) > to_date('2019-02-16', 'yyyy-MM') ) 
FROM shop_staff_relationvm ss WHERE ss.id_staff = s.id_staff and ss.id_shop !=2 LIMIT 1)
and 
(SELECT (MIN(to_date(to_char(ss.change_date, 'yyyy-MM'), 'yyyy-MM')) <= to_date('2019-02-16', 'yyyy-MM'))
FROM shop_staff_relationvm ss WHERE ss.id_staff = s.id_staff and ss.id_shop = 2) ) 
ELSE 
(SELECT (to_date(to_char(ss.change_date, 'yyyy-MM'), 'yyyy-MM') <= to_date('2019-02-16', 'yyyy-MM')) 
 FROM shop_staff_relationvm ss WHERE ss.id_staff = s.id_staff and ss.id_shop = 2 ) 
END);

Часть запроса, с которой у меня проблема:

((SELECT ((LEAD (to_date(to_char(ss.change_date, 'yyyy-MM'), 'yyyy-MM')) OVER (ORDER BY ss.id_staff DESC)) > to_date('2019-02-16', 'yyyy-MM') ) 
FROM shop_staff_relationvm ss WHERE ss.id_staff = s.id_staff and ss.id_shop !=2 LIMIT 1)
and 
(SELECT (MIN(to_date(to_char(ss.change_date, 'yyyy-MM'), 'yyyy-MM')) <= to_date('2019-02-16', 'yyyy-MM'))
FROM shop_staff_relationvm ss WHERE ss.id_staff = s.id_staff and ss.id_shop = 2))

Ваш вопрос касается одной таблицы, но ваш код включает другие таблицы.

Gordon Linoff 27.05.2019 13:12

да, потому что мне тоже нужны данные из таблицы персонала

Rii933 27.05.2019 14:11
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
2
2
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если вы хотите получить посох на конкретную дату, вы можете использовать distinct on.

select distinct on (ss.id_staff) ss.*
from shop_staff_relationvm ss 
where ss.change_date <= '2019-02-01'::date
order by ss.id_staff, ss.change_date desc;

С индексом shop_staff_relationvm(id_staff, change_date) это, вероятно, лучшее из возможных решений.

Чтобы определить, кто находится в конкретном магазине, используйте подзапрос:

select s.*
from (select distinct on (ss.id_staff) ss.*
      from shop_staff_relationvm ss 
      where ss.change_date <= '2019-02-01'::date
      order by ss.id_staff, ss.change_date desc
     ) s
where s.shop_id = 2;

Другие вопросы по теме