Может ли этот запрос быть оптимизирован? - PullRequest
0 голосов
/ 20 сентября 2018

Моя цель - выбрать запись по двум критериям, которые зависят друг от друга, и сгруппировать ее по другим критериям.

Я нашел решение, которое выбирает запись по одному критерию и группирует ее

SELECT *
FROM "records"
NATURAL JOIN (
  SELECT "group", min("priority1") AS "priority1" 
  FROM "records" 
  GROUP BY "group") AS "grouped"

Мне кажется, я понимаю концепцию этого поиска - выберите свойства, которые вам интересны, и сопоставьте их в исходной таблице - но когда я использую эту концепцию с двумя приоритетами, я получаю этого монстра

SELECT *
FROM "records"
  NATURAL JOIN (
    SELECT *
    FROM (
      SELECT "group", "priority1", min("priority2") AS "priority2"
      FROM "records"
      GROUP BY "group", "priority1") AS "grouped2"
    NATURAL JOIN (
      SELECT "group", min("priority1") AS "priority1"
      FROM "records"
      NATURAL JOIN (
        SELECT "group", "priority1", min("priority2") AS "priority2"
        FROM "records"
        GROUP BY "group", "priority1") AS "grouped2'"
      GROUP BY "group") AS "GroupNested") AS "grouped1"

Все, что я спрашиваю, не можетне написано ли лучше (оптимизировано и выглядит лучше)?

JSFIDDLE

---- Обновление ----

Цельявляется то, что я хочу выбрать один id для каждого group на priority1 и priority2 должен быть выбран в качестве первого, а затем приоритет2).

Пример: Когда у меня есть таблица records с id, group, priority1 и priority2 с данными:

id , group , priority1 , priority2
56 ,     1 ,         1 ,         2  
34 ,     1 ,         1 ,         3  
78 ,     1 ,         3 ,         1

результат должен быть 56,1,1,2.Для каждой группы сначала ищите мин из priority1, а затем мин из priority2.

Я пытался объединить max и min вместе (в одном запросе`, но он ничего не находит (у меня этого запроса больше нет).

Ответы [ 3 ]

0 голосов
/ 20 сентября 2018

возможно, это то, что вы ожидаете

 with dat as (
SELECT "group" grp
, priority1, priority2, id
, row_number() over (partition by "group" order by priority1) +
      row_number() over (partition by "group" order by priority2) as lp
FROM "records")

select dt.grp, priority1, priority2, dt.id
from dat dt
join (select min(lp) lpmin, grp from dat group by grp) dt1 on (dt1.lpmin = dt.lp and dt1.grp =dt.grp)
0 голосов
/ 20 сентября 2018

Просто используйте row_number().,,один раз:

select r.*
from (select r.*,
             row_number() over (partition by "group" order by priority1, priority2) as seqnum
      from records r
     ) r
where seqnum = 1;

Примечание: я бы посоветовал вам избегать natural join.Вместо этого вы можете использовать using (если вы не хотите явно включать сравнения на равенство).

Запросы с natural join очень трудно отлаживать, поскольку ключи join не указаны в списке.Хуже того, «естественные» объединения не используют должным образом объявленные отношения внешнего ключа.Они зависят просто от столбцов с одинаковыми именами.

В создаваемых мною таблицах они никогда не будут полезны, поскольку почти все таблицы имеют столбцы createdAt и createdBy.

0 голосов
/ 20 сентября 2018

EXISTS() на помощь!(Я сделал несколько переименований, чтобы избежать зарезервированных слов)


SELECT *
FROM zrecords r
WHERE NOT EXISTS (
    SELECT *
    FROM zrecords nx
    WHERE nx.zgroup = r.zgroup
    AND ( nx.priority1 < r.priority1
        OR nx.priority1 = r.priority1 AND nx.priority2 < r.priority2
        )
    );

Или, чтобы избежать логики AND / OR, сравните два кортежа напрямую:


SELECT *
FROM zrecords r
WHERE NOT EXISTS (
    SELECT *
    FROM zrecords nx
    WHERE nx.zgroup = r.zgroup
    AND (nx.priority1, nx.priority2) < (r.priority1 , r.priority2)
    );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...