Упражнение 71
Вот типичный неверный запрос
SELECT DISTINCT maker
FROM Product
WHERE model IN (SELECT model FROM PC);
[[ column ]] |
---|
[[ value ]] |
Ключевым моментом формулировки является слово “ВСЕ”. Давайте посмотрим на модели производителя E. Модели ПК, которые выпускает производитель E, дает следующий запрос:
SELECT model
FROM Product
WHERE maker='E' AND type='PC';
[[ column ]] |
---|
[[ value ]] |
Результат:
model |
---|
1260 |
2111 |
2112 |
А теперь проверим, какие из этих моделей имеются в таблице PC:
SELECT DISTINCT model
FROM PC
WHERE model IN(1260, 2111, 2112);
[[ column ]] |
---|
[[ value ]] |
Оказывается, что из трех моделей только одна - 1260 - имеется в таблице PC. По условию же задачи там должны находиться ВСЕ три модели производителя E.
Собственно, решение этой задачи сводится к операции реляционного деления, только для каждого производителя у нас свой делитель (его модели). В упрощенном виде операцию реляционного деления можно записать так:
A(a, b) DIVIDEBY B(b)
где делимое (А) представляет собой бинарное (двухатрибутное) отношение, а делитель (B) - унарное. Результатом являются такие значения из первого атрибута отношения A, для каждого из которых значения второго атрибута содержат ВСЕ значения делителя.
Операция реляционного деления не является примитивной. Это означает, что эту операцию можно выразить через другие (примитивные) реляционные операции. Избыточность реляционной алгебры, предложенной Коддом, обусловлена ориентаций на практическое применение. Язык SQL тоже избыточен, в чем нас убеждает каждая задача, которую можно решить разными способами. Несмотря на это, аналога операции реляционного деления в нем нет. :-)
В заключение приведу представление реляционного деления, выраженного через другие операции.
A DIVIDEBY B :=
A[a] EXCEPT ((A[a] TIMES B) EXCEPT A) [a]
Здесь A[a] означает проекцию отношения A на атрибут a; TIMES - декартово произведение. “Подстрочный” перевод на язык SQL может выглядеть следующим образом:
SELECT a FROM A
EXCEPT
SELECT a FROM (SELECT A.a, B.b FROM A, B
EXCEPT
SELECT a,b FROM A
) X;
Не следует использовать этот подстрочник как руководство к действию; есть более простые способы решить задачу. Впрочем, я не настаиваю. :-)