Вопрос SQL: исключая записи - PullRequest
       27

Вопрос SQL: исключая записи

2 голосов
/ 13 декабря 2008

У меня есть база данных (NexusDB (предположительно совместимая с SQL-92)), которая содержит таблицу Item, таблицу Category и таблицу ItemCategory «многие ко многим», представляющую собой просто пару ключей. Как и следовало ожидать, элементы относятся к нескольким категориям.

Я хочу, чтобы все конечные пользователи выбрали все элементы, которые

ItemID | CategoryID
--------------------------------
01 | 01
01 | 02
01 | 12

02 | 01
02 | 02
02 | 47

03 | 01
03 | 02
03 | 14
и т.д ...

Я хочу иметь возможность выбрать все ItemID, которые назначены для категорий X, Y и Z, но НЕ назначены для категорий P и Q.

Например, в приведенных выше примерах данные говорят, что я хотел бы получить все предметы, отнесенные к категориям 01 или 02, но НЕ 12 (получая предметы 02 и 03). Что-то вроде:

ВЫБЕРИТЕ ItemID WHERE (CategoryID IN (01, 02))

... и удалить из этого набора SELECT ItemID WHERE NOT (CategoryID = 12)

Вероятно, это довольно простой вопрос SQL, но он меня сейчас озадачивает. Любая помощь ж / б приветствуется.

Ответы [ 4 ]

2 голосов
/ 13 декабря 2008

Я хочу иметь возможность выбрать все ItemID, которые назначены Категории X, Y и Z, но НЕ назначены категориям P и Q.

Я не могу подтвердить из документации NexusDB на SELECT , что они поддерживают подзапросы, но они поддерживают LEFT OUTER JOIN и GROUP BY. Итак, вот запрос, который работает в рамках этих ограничений:

SELECT i1.ItemID
FROM ItemCategory i1
  LEFT OUTER JOIN ItemCategory i2
    ON (i1.ItemID = i2.ItemID AND i2.CategoryID IN ('P', 'Q'))
WHERE i1.CategoryID IN ('X', 'Y', 'Z')
  AND i2.ItemID IS NULL
GROUP BY i1.ItemID
HAVING COUNT(i1.CategoryID) = 3;
2 голосов
/ 13 декабря 2008

Вы можете попробовать с ИСКЛЮЧЕНИЕМ

SELECT ItemID FROM Table
EXCEPT
SELECT ItemID FROM Table
WHERE
CategoryID <> 12
1 голос
/ 13 декабря 2008
SELECT i.ItemID, ic.CategoryID FROM Item AS i
INNER JOIN ItemCategory ic
ON i.ItemID = ic.ItemID
WHERE ic.CategoryId = 1 OR ic.CategoryId = 2

Конечно, вы должны указать в предложении WHERE, какие категории вы хотите получить.

0 голосов
/ 13 декабря 2008

Для простого случая с небольшим и известным числом категорий вы можете просто использовать несколько объединений для проверки существования и несуществования:

SELECT
     ItemID
FROM
     Items I
INNER JOIN ItemCategories IC1 ON IC1.ItemID = I.ItemID AND IC1.CategoryID = '01'
INNER JOIN ItemCategories IC2 ON IC2.ItemID = I.ItemID AND IC2.CategoryID = '02'
LEFT OUTER JOIN ItemCategories IC3 ON IC3.ItemID = I.ItemID AND IC3.CategoryID = '12'
WHERE IC3.ItemID IS NULL

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

SELECT
     ItemID
FROM
     Items I
WHERE
     (
      SELECT COUNT(*)
      FROM ItemCategories IC1
      WHERE IC1.ItemID = I.ItemID
        AND IC.CategoryID IN
           (SELECT CategoryID FROM @MustHaves)
      ) = (SELECT COUNT(*) FROM @MustHaves) AND
      (
      SELECT COUNT(*)
      FROM ItemCategories IC1
      WHERE IC1.ItemID = I.ItemID
        AND IC.CategoryID IN
           (SELECT COUNT(*) FROM @MustNotHaves)
      ) = 0
...