加入 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 加入: