加入 id 或 null 并获得第一个结果
Join on id or null and get first result
我创建了以下查询:
select * from store str
left join(
select * from schedule sdl
where day = 3
order by
case when sdl.store_id is null then (
case when sdl.strong is true then 0 else 2 end
) else 1 end, sdl.schedule_id desc
) ovr on (ovr.store_id = str.store_id OR ovr.store_id IS NULL)
示例数据:
STORE
[store_id] [title]
20010 Shoes-Shop
20330 Candy-Shop
[SCHEDULE]
[schedule_id] [store_id] [day] [strong] [some_other_data]
1 20330 3 f 10% Discount
2 NULL 3 t 0% Discount
我想从 LEFT JOIN
得到的是 NULL store_id 的数据(全局计划条目 - 影响所有存储条目)或给定 store_id 的实际数据。
像这样加入查询,returns 结果顺序正确,但对于 NULL 和 store_id 匹配。在连接子句上使用 OR 语句是有意义的。
预期结果:
[store_id] [title] [some_other_data]
20010 Shoes-Shop 0% Discount
20330 Candy-Shop 0% Discount
当前结果:
[store_id] [title] [some_other_data]
20010 Shoes-Shop 0% Discount
20330 Candy-Shop 0% Discount
20330 Candy-Shop 10% Discount
如果有关于这个主题的更优雅的方法,我会很乐意遵循它。
我认为最简单的方法就是使用 distinct on
。那么问题是你如何订购它:
select distinct on (str.store_id) *
from store str left join
schedule sdl
on (sdl.store_id = str.store_id or sdl.store_id is null) and dl.day = 3
order by str.store_id,
(case when sdl.store_id is null then 2 else 1 end)
这将 return store
记录(如果可用),否则 schedule
值为 NULL
的记录。注意:您的查询具有 strength
的概念,但问题并未说明如何使用它。这可以很容易地修改以包括多个级别的优先级。
只要 ORDER BY
正确,DISTINCT ON
应该可以正常工作。基本上,在 schedule
中匹配 strong = TRUE
优先,然后匹配 store_id IS NOT NULL
:
SELECT DISTINCT ON (st.store_id)
st.store_id, st.title, sl.some_other_data
FROM store st
LEFT JOIN schedule sl ON sl.day = 3
AND (sl.store_id = st.store_id OR sl.store_id IS NULL)
ORDER BY NOT strong, store_id IS NULL;
之所以有效,是因为:
- Sorting null values after all others, except special
DISTINCT ON
的基础知识:
- Select first row in each GROUP BY group?
使用 LATERAL
连接的替代方案(Postgres 9.3+):
SELECT *
FROM store st
LEFT JOIN LATERAL (
SELECT some_other_data
FROM schedule
WHERE day = 3
AND (store_id = st.store_id OR store_id IS NULL)
ORDER BY NOT strong
, store_id IS NULL
LIMIT 1
) sl ON true;
关于 LATERAL
加入:
我创建了以下查询:
select * from store str
left join(
select * from schedule sdl
where day = 3
order by
case when sdl.store_id is null then (
case when sdl.strong is true then 0 else 2 end
) else 1 end, sdl.schedule_id desc
) ovr on (ovr.store_id = str.store_id OR ovr.store_id IS NULL)
示例数据:
STORE
[store_id] [title]
20010 Shoes-Shop
20330 Candy-Shop
[SCHEDULE]
[schedule_id] [store_id] [day] [strong] [some_other_data]
1 20330 3 f 10% Discount
2 NULL 3 t 0% Discount
我想从 LEFT JOIN
得到的是 NULL store_id 的数据(全局计划条目 - 影响所有存储条目)或给定 store_id 的实际数据。
像这样加入查询,returns 结果顺序正确,但对于 NULL 和 store_id 匹配。在连接子句上使用 OR 语句是有意义的。
预期结果:
[store_id] [title] [some_other_data]
20010 Shoes-Shop 0% Discount
20330 Candy-Shop 0% Discount
当前结果:
[store_id] [title] [some_other_data]
20010 Shoes-Shop 0% Discount
20330 Candy-Shop 0% Discount
20330 Candy-Shop 10% Discount
如果有关于这个主题的更优雅的方法,我会很乐意遵循它。
我认为最简单的方法就是使用 distinct on
。那么问题是你如何订购它:
select distinct on (str.store_id) *
from store str left join
schedule sdl
on (sdl.store_id = str.store_id or sdl.store_id is null) and dl.day = 3
order by str.store_id,
(case when sdl.store_id is null then 2 else 1 end)
这将 return store
记录(如果可用),否则 schedule
值为 NULL
的记录。注意:您的查询具有 strength
的概念,但问题并未说明如何使用它。这可以很容易地修改以包括多个级别的优先级。
ORDER BY
正确,DISTINCT ON
应该可以正常工作。基本上,在 schedule
中匹配 strong = TRUE
优先,然后匹配 store_id IS NOT NULL
:
SELECT DISTINCT ON (st.store_id)
st.store_id, st.title, sl.some_other_data
FROM store st
LEFT JOIN schedule sl ON sl.day = 3
AND (sl.store_id = st.store_id OR sl.store_id IS NULL)
ORDER BY NOT strong, store_id IS NULL;
之所以有效,是因为:
- Sorting null values after all others, except special
DISTINCT ON
的基础知识:
- Select first row in each GROUP BY group?
使用 LATERAL
连接的替代方案(Postgres 9.3+):
SELECT *
FROM store st
LEFT JOIN LATERAL (
SELECT some_other_data
FROM schedule
WHERE day = 3
AND (store_id = st.store_id OR store_id IS NULL)
ORDER BY NOT strong
, store_id IS NULL
LIMIT 1
) sl ON true;
关于 LATERAL
加入: