如果条件满足则选择 A 行,否则为每个组选择 B 行

Posted

技术标签:

【中文标题】如果条件满足则选择 A 行,否则为每个组选择 B 行【英文标题】:Select row A if a condition satisfies else select row B for each group 【发布时间】:2021-10-12 17:43:39 【问题描述】:

我们有 2 张桌子、预订和文档

预订

booking_id    |  name    
100           |  "Val1"  
101           |  "Val5"  
102           |  "Val6"

文档

doc_id  |  booking_id  |  doc_type_id  
6       |  100         | 1
7       |  100         | 2
8       |  101         | 1
9       |  101         | 2
10      |  101         | 2

我们需要这样的结果:

booking_id | doc_id
100        | 7
101        | 10

本质上,我们正在尝试获取每次预订的最新文档记录,但如果存在 doc_type_id 2,则选择 doc type 2 的最新记录,否则选择 doc_type_id 1 的最新记录。

这是否可以通过性能友好的查询来实现,因为我们需要在非常庞大的查询中应用它?

【问题讨论】:

我使用的是 10.5.4 【参考方案1】:

您可以使用FIRST_VALUE() 窗口函数来做到这一点,方法是对每个booking_id 的行进行正确排序,以便首先返回带有doc_type_id = 2 的行:

SELECT DISTINCT booking_id,  
       FIRST_VALUE(doc_id) OVER (PARTITION BY booking_id ORDER BY doc_type_id = 2 DESC, doc_id DESC) rn
FROM docs;

如果您想返回完整的行,那么您可以使用ROW_NUMBER() 窗口函数:

SELECT booking_id, doc_id, doc_type_id  
FROM (
  SELECT *, 
         ROW_NUMBER() OVER (PARTITION BY booking_id ORDER BY doc_type_id = 2 DESC, doc_id DESC) rn
  FROM docs
) t
WHERE rn = 1;

【讨论】:

我对多个列做了如下操作,这样我就可以避免子查询希望获得性能 SELECT DISTINCT booking_id, FIRST_VALUE(doc_id) OVER (W) doc_id, FIRST_VALUE(doc_type_id) OVER (W) doc_type_id FROM docs WINDOW W AS (PARTITION BY booking_id ORDER BY doc_type_id = 2 DESC, doc_id DESC);

以上是关于如果条件满足则选择 A 行,否则为每个组选择 B 行的主要内容,如果未能解决你的问题,请参考以下文章

从每个组中选择1行匹配或回退

PHP / SQL:如果在表A和表B中更新后满足条件,则更新表C

GROUP BY 如果组中至少一个值满足条件,则创建组

从满足条件A的组中选择行。如果不是,请给我一行满足条件B的行

条件选择

选择满足 SQL 中条件的元组列表