如何从组中选择特定行?

问题描述 投票:0回答:2

我有一个包含几列的表:

id |  Source  |  Mode   | SponsorID | Code  | ...
1    source1    Paper     123        7102
2    source2    Paper     123        7102
3    source2    Paper     123        7101
4    source1    Paper     123        7101
5    source2    Paper     123        1010
6    source1    Paper     345        1010
7    source2    Paper     345        7102
8    source1    Paper     345        1010
9    source2    Paper     345        7102
10   source1    Paper     345        7102
11   source1    Paper     678        1010
12   source2    Paper     678        1010
13   source1    Paper     678        1010
14   source2    Paper     678        1010
15   source1    Paper     678        1010

我想将以上记录按SponsorID分组,只想根据code列中的值选择一个记录。在SponsorID组中,我只希望选择具有代码7101的记录。如果该值在代码列中不存在,我希望能够在代码列中选择值为7102的记录。如果7102不存在,我想选择1010作为记录。因此最终输出应类似于:

1    source1    Paper     123        7101
2    source2    Paper     345        7102
3    source1    Paper     678        1010

我尝试使用分区和大小写,但没有成功。如果有人可以帮助,将不胜感激。

sql postgresql group-by sql-order-by greatest-n-per-group
2个回答
0
投票

使用distinct on以及一些过滤和排序:

select distinct on (SponsorID) t.*
from t
where code in (7101, 7102, 1010)
order by SponsorId, (case code when 7101 then 1 when 7102 then 2 else 3 end);

0
投票

DISTINCT ON,就像Gordon提供的一样,完全有效且简单。基础知识:

您可能会使用带有unnest()WITH ORDINALITY的构造,并且仅提供具有按您的喜好排序的代码的数组:

SELECT DISTINCT ON (SponsorID) t.*
FROM   unnest('{7101, 7102, 1010}'::int[]) WITH ORDINALITY x(code, ord)
JOIN   tbl t USING (code)
ORDER  BY t.SponsorID, x.ord;

参见:

简单索引有助于性能if感兴趣的代码不太常见:

CREATE INDEX ON tbl (code);

但是您的样本值建议每个(SponsorID, code)许多行。所以两件事:

1。正确性

[如果有code = 7101等,则定义要选择的行。“最小的id开头”。您can只需从上方将另一个ORDER BY表达式附加到查询中即可:

...
ORDER  BY t.SponsorID, x.ord, t.id;

但是请考虑...

2。效果

假设有一个表sponsor,每个赞助者有1行(通常是这样),请考虑以下更复杂的查询:

SELECT t.*
FROM   sponsor s
CROSS  JOIN LATERAL (
             (SELECT * FROM tbl t WHERE t.SponsorID = s.id AND code = 7101 ORDER BY id LIMIT 1) -- ORDER BY id???
   UNION ALL (SELECT * FROM tbl t WHERE t.SponsorID = s.id AND code = 7102 ORDER BY id LIMIT 1)
   UNION ALL (SELECT * FROM tbl t WHERE t.SponsorID = s.id AND code = 1010 ORDER BY id LIMIT 1)
   LIMIT 1
   ) t
;

db <>小提琴here

与该索引合作:

CREATE INDEX ON tbl (SponsorID, code, id);

现在我们获得了快速的索引扫描,只读取了我们实际需要的行。

如果您不关心“最小的id优先”,请从查询和索引中删除。

甚至有些方法都没有sponsor表,但是我们进入的太深了……请参阅:

© www.soinside.com 2019 - 2024. All rights reserved.