我有一张表格(shop_staff_relationvm
)保存了员工和商店之间的关系。
它有3列:id_shop
,id_staff
和change_date
。
id_staff
=>人员外键id_shop
=>购买外键change_date
==>每当创建新的职员商店关系时,我都会保存设置日期(职员商店可能会多次更改) 3个abov列代表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将拥有员工A,商店2将没有员工,商店3将没有员工
假设我们有requestMonth = 03-2019
然后:商店1将没有员工,商店2将拥有员工A,商店3将没有员工
假设我们有requestMonth = 06-2019
然后:商店1没有员工,商店2没有员工,商店3没有员工A
这是我想出的公式:
first date of relation <= requestMonth <= first date of next relation
获取关系的第一个日期没有问题,但是获取下一个关系的第一个日期(我得出结论是离关系的第一个最近的值)时遇到了问题。
PS:我正在使用JPA本机查询
我尝试使用order by (change_date - first date of relation)
来获取与第一个关系日期最接近的值。却总能为我带来最大值(在上述示例中,总能给我05-2019
月)
我还尝试使用LEAD
来获取下一个最接近的值。但是,使用上面的示例:
对于
requestMonth = 02-2019
: LEAD等于03-2019 =>正确对于
requestMonth = 03-2019
: LEAD等于01-2019 =>错误=>应该为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))
答案 0 :(得分: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;