Реляционный отдел - имитация «ТОЛЬКО В» - PullRequest
0 голосов
/ 14 января 2019

Я пытаюсь написать запрос в Oracle SQL, который принимает два параметра и находит по всей таблице все экземпляры, где только один или происходит, независимо от того, сколько из них есть в поиске. Вот пример того, что я ищу:

| ID  | FileType | COUNT(FileType) |
|-----|----------|-----------------|
| 1   | txt      | 1               |
| 1   | png      | 3               |
| 1   | jpg      | 2               |
====================================
| 2   | txt      | 0               |
| 2   | png      | 6               |
| 2   | jpg      | 0               |
====================================
| 3   | txt      | 0               |
| 3   | png      | 0               |
| 3   | jpg      | 5               |
====================================
| 4   | txt      | 0               |
| 4   | png      | 3               |
| 4   | jpg      | 1               |
====================================
| 5   | txt      | 5               |
| 5   | png      | 0               |
| 5   | jpg      | 3               |

Моя цель состоит в том, чтобы взять все идентификаторы, используя ТОЛЬКО png ИЛИ jpg, и опустить остальные, поэтому я хочу, чтобы только идентификаторы 2, 3 и 4 возвращались.

Я попытался найти решения здесь и не нашел ничего, что соответствовало бы моему случаю. (Ближайший вопрос: SQL выбирает строки с определенным значением )

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

SELECT DISTINCT ID, FileType, COUNT(FileType)
FROM Table ta
WHERE (ta.FileType = 'jpg' or ta.FileType = 'png') and
NOT EXISTS
    (SELECT *
     FROM Table tb
     WHERE ta.FileType = tb.FileType and
     (tb.FileType != 'jpg' or tb.FileType != 'png'))
GROUP BY ID, FileType;

Когда я пытаюсь это сделать, я не получаю результатов. У кого-нибудь есть идеи, где я ошибся?

Ответы [ 3 ]

0 голосов
/ 14 января 2019

Вы можете использовать операторы множества:

SELECT ID FROM tab WHERE FileType IN ('jpg', 'png')
MINUS
SELECT ID FROM tab WHERE FileType NOT IN ('jpg', 'png')

Предположение: FileType не обнуляется.


Обработка NULL:

SELECT ID FROM tab WHERE FileType IN ('jpg', 'png')
MINUS
SELECT ID 
FROM (SELECT * FROM tab WHERE FileType IS NOT NULL) 
WHERE FileType NOT IN ('jpg', 'png')
0 голосов
/ 14 января 2019

Просто используйте таблицу "helper":

WITH TypeCounts AS
(
  SELECT ID, FileType, COUNT(*) AS CNT
  FROM Table
  GROUP BY ID, FileType
)
SELECT *
FROM Table
LEFT JOIN TypeCounts txt ON txt.ID = Table.ID AND txt.FileType = 'txt'
LEFT JOIN TypeCounts jpg ON jpg.ID = Table.ID AND jpg.FileType = 'jpg'
LEFT JOIN TypeCounts png ON png.ID = Table.ID AND png.FileType = 'png'
WHERE COALESCE(txt.CNT,0) = 0 AND
    ( COALESCE(jpg.CNT,0) > 0 OR COALESCE(png.CNT,0) > 0)

Что приятно в этом решении, так это то, что оно очень ясно представляет бизнес-правила и поэтому его легче поддерживать.

0 голосов
/ 14 января 2019

Вы рядом. Просто посмотрите, сколько у вас разных типов файлов. Вот ваши идентификаторы:

SELECT ID
FROM Table ta
GROUP BY ID
HAVING count(distinct FileType) = 1 and max(ta.FileType) in ('jpg','png');

Обновление: верхний сбой для случая 4.

Это сделает это, но это ужасно:

SELECT ID
FROM Table ta
GROUP BY ID
HAVING count(distinct FileType) <= 2 
   and max(ta.FileType) in ('jpg','png') 
   and min(ta.FileType) in ('jpg','png');

Это ужасно, потому что вы не можете расширить его на 3 значения.

...