Постгрес SQL. Выберите столбец, который коррелирует со значением в агрегатной функции

Вот таблица «items», содержащая более 10 строк:

+-----+-----------+-----------+----------+
| id  | item_name | category  | quantity |
+=====+===========+===========+==========+
| 3   | item33    | category1 | 5        |
+-----+-----------+-----------+----------+
| 2   | item52    | category5 | 1        |
+-----+-----------+-----------+----------+
| 1   | item46    | category1 | 3        |
+-----+-----------+-----------+----------+
| 4   | item11    | category3 | 2        |
+-----+-----------+-----------+----------+
| ... | ...       | ...       | ...      |
+-----+-----------+-----------+----------+

Значения в столбце «элементы» уникальны, значения в столбце «категория» — не уникальны.

Задача:

  1. Удалить дубликаты категорий: если категория содержит более 1 элемента, брать строку с минимальным «id».
  2. Упорядочить результаты по «количеству» (ASC).
  3. Возьмите 10 строк: первые 5 и случайные 5 из остальных результатов вывода данных.

Итак, таблица заказов (после подзадачи №2) должна выглядеть так:

+-----+-----------+-----------+----------+
| id  | item_name | category  | quantity |
+=====+===========+===========+==========+
| 2   | item52    | category5 | 1        |
+-----+-----------+-----------+----------+
| 4   | item11    | category3 | 2        |
+-----+-----------+-----------+----------+
| 1   | item46    | category1 | 3        |
+-----+-----------+-----------+----------+
| ... | ...       | ...       | ...      |
+-----+-----------+-----------+----------+

Я знаю, как исключить дубликаты для категорий:

SELECT min(id) as id, category
FROM items
GROUP BY category

Но я не знаю, как заказать его по количеству. Если я попытаюсь добавить «количество» в строку «выбрать», а затем сделать «ЗАКАЗАТЬ ПО количеству», я получаю сообщение об ошибке: «столбец «количество» должен отображаться в предложении GROUP BY или использоваться в агрегатной функции».

Если есть способ добавить этот столбец «количество» в вывод данных (значение в этом столбце должно коррелировать с результирующим значением «id» (т.е. «min (id)»))? А затем сделать заказ и выбор строк...

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
0
782
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вам нужно использовать аналитическую функцию следующим образом:

Select * from
(Select t.*,
       Row_number() over (order by quantity) as rn_q
 from
(Select t.*,
       Row_number() over (partition by category order by id) as rn
  From your_table) t
Where rn = 1) t
Order by case when rn_q <= 5 then quantity else 6 end;
Ответ принят как подходящий

Рассмотрите возможность присоединения вашего агрегированного запроса к данным на уровне единиц для всех столбцов, включая quantity:

SELECT i.id, i.item_name, i.category, i.quantity
FROM items i
INNER JOIN 
  (SELECT category, min(id) AS min_id
   FROM items
   GROUP BY category) agg
 ON i.id = agg.min_id
 AND i.category = agg.category
ORDER BY i.quantity

Для разделения 5 лучших и случайных 5 интегрируйте объединение с CTE, чтобы сохранить набор результатов:

WITH sub AS (
  SELECT i.id, i.item_name, i.category, i.quantity
  FROM items i
  INNER JOIN 
    (SELECT category, min(id) AS min_id
     FROM items
     GROUP BY category) agg
   ON i.id = agg.min_id
   AND i.category = agg.category
)

-- TOP 5 ROWS
SELECT id, item_name, category, quantity
FROM sub
ORDER BY i.quantity
LIMIT 5

UNION

-- RANDOM ROWS OF NON-TOP 5
SELECT id, item_name, category, quantity
FROM 
  (SELECT id, item_name, category, quantity
   FROM sub
   ORDER BY i.quantity
   OFFSET 5) below5
ORDER BY random()
LIMIT 5

Это решение работает лучше всего для меня, потому что с моим небольшим знанием Postgres я могу, по крайней мере, понять этот код: D Спасибо за помощь всем, несмотря ни на что. Я очень ценю это.

Ivan 26.12.2020 02:40

Приятно слышать и рад помочь! Это решение также работает в других СУБД и не ограничивается методами диалекта Postgres. Удачного SQL!

Parfait 26.12.2020 05:45

По сути, DISTINCT ON хорошо работает в Postgres. Видеть:

Простое (правильное!) решение:

WITH dist_cat AS (
   SELECT t, row_number() OVER (ORDER BY quantity, id) AS rn   -- added id as tiebreaker
   FROM  (
      SELECT DISTINCT ON (category) *
      FROM   tbl
      ORDER  BY category, id
      ) t  -- distinct categories
   ORDER  BY ORDER BY quantity, id  -- match sort for row_number()
   )
SELECT (t).*
FROM   dist_cat
WHERE  rn <= 5

UNION ALL   -- not just UNION
(  -- parentheses required
SELECT (t).*
FROM   dist_cat
WHERE  rn > 5
ORDER  BY random()
LIMIT  5
);

Добавлено id в качестве разрешения на сортировку, так как сортировка по quantity вряд ли является детерминированной. Поместите туда любое уникальное выражение, соответствующее вашим требованиям. Или пропустите его, если вы согласны с произвольными результатами, которые могут меняться при каждом вызове.

Тип строки t предназначен для удобства, поэтому нам не нужно указывать все имена столбцов по буквам, и при этом избавиться от добавленного rn в результате, который не был запрошен.

Я решил упорядочить строки в CTE и добавить номер строки rn, чтобы избежать дополнительной операции сортировки.

Дополнительные 5 случайных строк выбираются действительно случайным образом, а не просто произвольно.

Используйте UNION ALL, а не только UNION. Потому что это правильно для того, чем мы занимаемся, и к тому же дешевле. Но также для сохранения порядка сортировки из CTE; UNION может напортачить, пытаясь удалить дубликаты - тщетно.

Для больших таблиц, в зависимости от распределения данных, могут быть (намного) более быстрые методы...

... для получения уникальных категорий:

.. для получения случайных строк:

Другие вопросы по теме

В psql, как запустить цикл для запроса Select с CTE и получить вывод, показанный, если я запускаю его в базе данных только для чтения?
Как в psql запустить цикл для запроса Select с CTE и получить вывод, отображаемый в базе данных только для чтения?
Django psycopg2.errors.StringDataRightTruncation: слишком длинное значение для изменяющегося символа типа (200)
Как получить случайную запись из БД?
Node.js (TypeScript) Клиент Postgres не выполняет оператор вставки в Pool.query, а обратный вызов не выполняется
Какая привилегия необходима пользователю для создания таблицы в другой схеме
Перебрать каждый элемент в массиве JSON и соединиться со строками
Rails на JSONB «где» несколько условий поиска во вложенном массиве объектов
Как добавить аргументы конфигурации в контейнер службы postgres в Github Action?
Почему объединение двух запросов выполняется быстрее, чем один из объединенных запросов?