Как выбрать конкретную c строку из группы? - PullRequest
0 голосов
/ 07 апреля 2020

У меня есть таблица с несколькими столбцами:

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

Я пробовал использовать разделы и регистр, но безуспешно.
Был бы очень признателен, если кто-то может помочь.

Ответы [ 2 ]

0 голосов
/ 07 апреля 2020

DISTINCT ON, как и в случае с Гордоном, вполне допустимо и просто. Основы:

Вы можете использовать конструкцию с 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;

См .:

Простой индекс помогает производительности , если коды интересов не слишком распространены:

CREATE INDEX ON tbl (code);

Но Ваши выборочные значения предполагают, что много строк на (SponsorID, code). Итак, 2 вещи:

1. Корректность

Определите, какую строку выбрать при наличии нескольких, с помощью code = 7101 et c. Что-то вроде "самый маленький id первый" . Вы можете просто добавить к запросу еще одно ORDER BY выражение:

...
ORDER  BY t.SponsorID, x.ord, <b>t.id</b>;

Но рассмотрим ...

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 <> fiddle здесь

В сотрудничестве с этим индексом:

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

Теперь мы получаем быстрое сканирование индекса, только чтение строк, которые нам действительно нужны.

Если вас не волнует «сначала самое маленькое id», обрежьте его из запроса и индекса.

Есть даже способы без таблицы sponsor, но мы слишком углубляемся ... См .:

0 голосов
/ 07 апреля 2020

Использование 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);
...