#sql #sqlite
#sql #sqlite
Вопрос:
Учитывая приведенный ниже набор данных, я хочу запустить запрос, чтобы выделить любые «пары», которые не состоят из «левого» и «правого».
--------- ----------- --------------- ----------------------
| Pair_Id | Pair_Name | Individual_Id | Individual_Direction |
--------- ----------- --------------- ----------------------
| 1 | A | A1 | Left |
| 1 | A | A2 | Right |
| 2 | B | B1 | Right |
| 2 | B | B2 | Left |
| 3 | C | C1 | Left |
| 3 | C | C2 | Left |
| 4 | D | D1 | Right |
| 4 | D | D2 | Left |
| 5 | E | E1 | Left |
| 5 | E | E2 | Right |
--------- ----------- --------------- ----------------------
В этом случае пара 3 ‘C’ имеет два левых. Поэтому я бы хотел отобразить следующее:
--------- ----------- --------------- ----------------------
| Pair_Id | Pair_Name | Individual_Id | Individual_Direction |
--------- ----------- --------------- ----------------------
| 3 | C | C1 | Left |
| 3 | C | C2 | Left |
--------- ----------- --------------- ----------------------
Ответ №1:
Вы можете просто использовать not exists
:
select t.*
from t
where not exists (select 1
from t t2
where t2.pair_id = t.pair_id and
t2.Individual_Direction <> t.Individual_Direction
) ;
С включенным индексом (pair_id, Individual_Direction)
это должно быть не только наиболее кратким решением, но и самым быстрым.
Если вы хотите быть уверены, что есть пары (приведенное выше возвращает синглтоны):
select t.*
from t
where not exists (select 1
from t t2
where t2.pair_id = t.pair_id and
t2.Individual_Direction <> t.Individual_Direction
) and
exists (select 1
from t t2
where t2.pair_id = t.pair_id and
t2.Individual_ID <> t.Individual_ID
);
Вы также можете сделать это с помощью оконных функций:
select t.*
from (select t.*,
count(*) over (partition by pair_id) as cnt,
min(status) over (partition by pair_id) as min_status,
max(status) over (partition by pair_id) as max_status
from t
) t
where cnt > 1 and min_status <> max_status;
Комментарии:
1. У меня есть несколько пар в моей таблице, которые имеют только один экземпляр (т. Е. Только левый или правый) (в моем случае использования это нормально). Я хочу только идентифицировать дубликаты (т. Е. Два левых). Я думаю, что могу добиться этого, введя количество > 2?
2. @JHarley1: Добавить
AND COUNT(*) > 1
к Тиму, ИМЕЮЩЕМУ3. @JHarley1 . . . Ваш вопрос таков: «Учитывая приведенный ниже набор данных, я хочу выполнить запрос, чтобы выделить любые «пары», которые не состоят из «левого» и «правого».», поэтому два права будут совпадать. Я отредактировал вопрос, чтобы отфильтровать одиночные элементы. Также странно, что вы приняли ответ, который не соответствует этому условию.
4. @GordonLinoff, рад, что есть хороший способ решения проблемы с помощью оконной функции. однако есть 2 исправления: 1) должно быть Individual_Direction вместо status для имени столбца; 2) минимальный статус должен быть = max status, а не <>, так как он хочет только слева.
Ответ №2:
Один из вариантов использует агрегирование:
WITH cte AS (
SELECT Pair_Name
FROM yourTable
WHERE Individual_Direction IN ('Left', 'Right')
GROUP BY Pair_Name
HAVING MIN(Individual_Direction) = MAX(Individual_Direction)
)
SELECT *
FROM yourTable
WHERE Pair_Name IN (SELECT Pair_Name FROM cte);
HAVING
Предложение, используемое выше, утверждает, что совпадающая пара имеет как минимальное, так и максимальное направление, которые одинаковы. Это означает, что такая пара имеет только одно направление.
Как и в случае с ответом Гордона, индекс на (Pair_Name, Individual_Direction)
может повысить производительность:
CREATE INDEX idx ON yourTable (Pair_Name, Individual_Direction);
Ответ №3:
Должен быть элегантный способ использования функции окна, чем то, что я написал:
WITH ranked AS
(
SELECT *, RANK() OVER(ORDER BY Pair_Id, Pair_Name, Individual_Direction) AS r
FROM pairs
),
counted AS
(
SELECT Pair_Id, Pair_Name, Individual_Direction,r, COUNT(r) as times FROM ranked
GROUP BY Pair_Id, Pair_Name, Individual_Direction, r
HAVING COUNT(r) > 1
)
SELECT ranked.Pair_Id, ranked.Pair_Name, ranked.Individual_Id, ranked.Individual_Direction FROM ranked
RIGHT JOIN counted
ON ranked.Pair_Id=counted.Pair_Id
AND ranked.Pair_Name=counted.Pair_Name
AND ranked.Individual_Direction=counted.Individual_Direction