#sql #postgresql
Вопрос:
У меня есть два стола, boxes
и things
они частично моделируют склад.
Коробка может
- содержать одну вещь
- содержит одну или несколько коробок
- быть пустым
Существует только один уровень вложенности: ящик может быть родителем или ребенком, но не бабушкой и дедушкой.
Я хочу определить родительские поля, которые удовлетворяют этим критериям:
- заводите детей более чем в одном месте
- следует учитывать только дочерние поля, связанные с количеством > 0
Используя данные примера, следует выбрать поле с идентификатором 2, поскольку в нем есть дочерние элементы с количествами в двух местах. Вставка 1 должна быть отклонена, потому что все ее дети находятся в одном месте, а вставка 3 должна быть отклонена, потому что, хотя у нее есть дети в двух местах, только в одном месте есть положительное количество.
Запрос должен работать на всех поддерживаемых версиях Postgresql. Обе таблицы содержат около двух миллионов записей.
Установка:
DROP TABLE IF EXISTS things;
DROP TABLE IF EXISTS boxes;
CREATE TABLE boxes (
id serial primary key,
box_id integer references boxes(id)
);
CREATE TABLE things (
id serial primary key,
box_id integer references boxes(id),
place_id integer,
quantity integer
);
INSERT INTO boxes (box_id)
VALUES (NULL), (NULL), (NULL), (1), (1), (2), (2), (3), (3);
INSERT INTO things (box_id, place_id, quantity)
VALUES (4, 1, 1), (5, 1, 1), (6, 2, 1), (7, 3, 1), (8, 4, 1), (9, 5, 0);
Я придумал это решение
WITH parent_places AS (
SELECT DISTINCT ON (b.box_id, t.place_id) b.box_id, t.place_id
FROM boxes b
JOIN things t ON b.id = t.box_id
WHERE t.quantity > 0
)
SELECT box_id, COUNT(box_id)
FROM parent_places
GROUP BY box_id
HAVING COUNT(box_id) > 1;
но мне интересно, пропустил ли я более очевидное решение (или в моем решении есть какие-либо ошибки, которые я упустил из виду).
Комментарии:
1. В коробке может быть либо одна коробка, либо (или) одна вещь внутри? Правильно ли я вас понял ?
2. Если это так, то это может быть не коробка с 2 вещами в ней. В вашем тестовом примере я вижу 2 коробки в коробках 1, 2, 3.. В соответствии с примером кажется, что в коробке может быть несколько коробок, но одна вещь. Пожалуйста, уточните ограничения на данные.
3. Ах, извините, я был слишком сосредоточен на «вещах». Коробка может содержать ноль или более коробок. Я отредактирую вопрос, чтобы уточнить. Спасибо
Ответ №1:
Единственный способ, чтобы в коробке были вещи с разными свойствами расположения, — это только тогда, когда в коробке есть несколько коробок с вещами в них.
SELECT
b2.box_id, COUNT(DISTINCT place_id)
FROM
boxes b2
JOIN things t ON b2.id = t.box_id AND quantity > 0
WHERE
b2.box_id IS NOT NULL
GROUP BY
b2.box_id
HAVING
COUNT(DISTINCT place_id) > 1;
Я не вижу причин для использования CTE, как в вашем примере. Я думаю, вам следует использовать самый простой запрос, который выполняет эту работу.
Комментарии:
1. «Я думаю, что вы должны использовать самый простой запрос, который выполняет эту работу» -> именно моя мотивация для того, чтобы задать вопрос! Спасибо, что нашли время ответить.
2. я рад помочь 🙂