Выборка со "сложным" условием PostgreSQL
Имеется такая выборка
SELECT queue,klid,type,shipno WHERE shipno = 25290
Результат этой выборки;
| queue | klid | type | shipno |
|---|---|---|---|
| 27 | 1845 | 2 | 25290 |
| 27 | 1921 | 1 | 25290 |
| 28 | 1921 | 2 | 25290 |
| 29 | 1963 | 1 | 25290 |
Условие для выборки такое: если количество повторяющихся queue > 1 то для каждого такого повторяющегося уникального queue оставляем только строку с type = 2
В результате должены появится вот такой вывод
| queue | klid | type | shipno |
|---|---|---|---|
| 27 | 1845 | 2 | 25290 |
| 28 | 1921 | 2 | 25290 |
| 29 | 1963 | 1 | 25290 |
Подскажите как это реализовать в PostgreSQL?
Ответы (2 шт):
Вы не указали название таблицы поэтому я использовал в ее качестве some_table
SELECT
st1.queue,
st1.klid,
st1.type,
st1.shipno
FROM some_table st1
INNER JOIN (SELECT
st2.queue,
count(*) as cnt
FROM some_table st2
GROUP BY st2.queue) cnts
ON st1.queue = cnts.queue
WHERE
(cnts.cnt = 1) OR
(cnts.cnt > 1 AND st1.type = 2)
;
Что я тут сделал:
- я сделал запрос подсчитывающий количество строк сгруппированных по значению
queue - и используя результат данного вспомогательного запроса как временную таблицу - присоединил его к результатам выборки
some_table, соединив их по значениямqueue, после чего в основной выборке нам стало доступно количество строк с таким queue в таблице. - после этого в условии можно указать
- либо вы уникальны и идете в выборку как есть
- либо вас много и выбираются только те, у которых
type=2
вот и все.
Поступил именно так, ибо мне не очень хотелось делать несколько подзапросов в условии.
Вариант с JOINом казался мне чуть элегантнее
Значения таблицы без дополнительных условий выборки
| queue | klid | type | shipno |
|---|---|---|---|
| 1 | 5731 | 1 | 9764 |
| 2 | 9465 | 1 | 1346 |
| 2 | 6789 | 2 | 5863 |
| 3 | 2837 | 1 | 7584 |
| 4 | 4896 | 1 | 9568 |
| 4 | 3658 | 2 | 3265 |
| 5 | 7452 | 1 | 2451 |
| 6 | 2365 | 1 | 6458 |
| 6 | 4587 | 2 | 2552 |
Результаты выполнения запроса в данном ответе
| queue | klid | type | shipno |
|---|---|---|---|
| 1 | 5731 | 1 | 9764 |
| 2 | 6789 | 2 | 5863 |
| 3 | 2837 | 1 | 7584 |
| 4 | 3658 | 2 | 3265 |
| 5 | 7452 | 1 | 2451 |
| 6 | 4587 | 2 | 2552 |
Простой вариант: вам надо сначала создать таблицу для queue, где будут номера queue с повторами (28 и 29), а затем проверять на вхождение в неё.
Например, код может быть таким (привожу вместе с тестовой базой, сделанной для проверки). Учитите, что пишу на mySQL, но логика для PostgreSQL сохранится. Можете повторяющийся кусок свести к алиасу, а также в условие WHERE добавить shipno = 25290, если всё захотите одним запросом сделать.
CREATE TABLE calls(
queue INT,
klid INT,
type INT,
shipno INT
);
INSERT INTO calls (queue,klid,type,shipno)
VALUES
(27,1845,2,25290),
(27,1921,1,25290),
(28,1921,2,25290),
(29,1963,1,25290)
;
SELECT * FROM calls;
SELECT queue,klid,type,shipno
FROM calls
WHERE (queue NOT IN (
SELECT queue
FROM calls
GROUP BY queue
HAVING COUNT(queue) = 1
) AND type = 2)
OR
queue IN (
SELECT queue
FROM calls
GROUP BY queue
HAVING COUNT(queue) = 1
);
Результат:
Affected rows: 0
Affected rows: 4
Query result:
+-------+------+------+--------+
| queue | klid | type | shipno |
+-------+------+------+--------+
| 27 | 1845 | 2 | 25290 |
| 27 | 1921 | 1 | 25290 |
| 28 | 1921 | 2 | 25290 |
| 29 | 1963 | 1 | 25290 |
+-------+------+------+--------+
Affected rows: 4
Query result:
+-------+------+------+--------+
| queue | klid | type | shipno |
+-------+------+------+--------+
| 27 | 1845 | 2 | 25290 |
| 28 | 1921 | 2 | 25290 |
| 29 | 1963 | 1 | 25290 |
+-------+------+------+--------+
Affected rows: 3