Книги и статьи по SQL Rambler's Top100 Switch language to: English 23 сентября 2019 г. 12:16:50


www.sql-ex.ru
Skip Navigation Links  

 

Print  Версия для печати

На главную страницу

Характерные ошибки при решении упражнений. Задача 23

Моисеенко С.И.

Найдите производителей, которые производили бы как ПК со скоростью не менее 750 МГц, так и ПК-блокноты со скоростью не менее 750 МГц. Вывести: Maker

Эта задача поясняется в FAQ на сайте.

SELECT DISTINCT maker FROM product
  WHERE model IN (SELECT model FROM pc WHERE speed>=750)
   OR
   model IN (SELECT model FROM laptop WHERE speed>=750)

В приведенном решении в результирующий набор попадет также и производитель, выпускающий что-нибудь одно: либо ПК, либо ПК-блокноты, т.к. для попадания в результирующий набор достаточно выполнения одного из условий, соединяемых оператором OR. Что не удовлетворяет условиям задачи и совершенно справедливо отвергается системой.

Перефразируя Толстого, скажу: "Все правильные решения правильны одинаково, а неправильные - неправильны по-своему". Вот еще одна попытка "изменить" ситуацию в лучшую сторону:

SELECT DISTINCT maker FROM product a, pc b, laptop c
   WHERE b.speed >= 750 AND c.speed >= 750
   AND
   (a.model = b.model OR a.model = c.model)

Используя равенство предикатов,

x AND (y OR z) = (x AND y) OR (x AND z)

выполним синтаксические преобразования рассматриваемого запроса:

SELECT DISTINCT maker FROM product a, pc b, laptop c
   WHERE ((b.speed >= 750 AND c.speed >= 750)
   AND a.model = b.model)
      OR
   ((b.speed >= 750 AND c.speed >= 750)
   AND a.model = c.model)

В результирующий набор попадут строки, отвечающие хотя бы одному из предикатов, соединяемых оператором OR. Рассмотрим, например, запрос с первым предикатом:

SELECT DISTINCT maker FROM product a, pc b, laptop c
   WHERE ((b.speed >= 750 AND c.speed >= 750)
   AND a.model = b.model)

Перепишем его в синтаксически более удобной форме:

SELECT DISTINCT maker
   FROM product a JOIN pc b ON a.model = b.model,
      laptop c
   WHERE (b.speed >= 750 AND c.speed >= 750)

и далее

SELECT DISTINCT maker FROM
(
   SELECT maker FROM product a JOIN pc b ON a.model = b.model
       WHERE b.speed >= 750
) x,
(
   SELECT * FROM laptop c WHERE (c.speed >= 750)
) y

Теперь, пожалуй, уже можно проанализировать. Первый подзапрос, который мы обозначили "х" соединяет по внешнему ключу таблицу PC с таблицей Product, отбирая производителей ПК со скоростью >=750. Второй ("y") отбирает модели ПК-блокнотов со скоростью >=750.

То, как соединяются "x" и "y", называется декартовым произведением. Т.е. производитель требуемых ПК будет в результирующем наборе сочетаться с КАЖДОЙ моделью ПК-блокнота, даже если она произведена ДРУГИМ производителем.

Не знаю, как Толстой, а я, кажется, ошибся. Грабли те же, только в других кустах, а именно, мы опять получим производителей, которые могут производить только что-то одно. А "кусты" другие потому, что если НИКТО не производит ПК-блокноты с требуемой скоростью, то мы получим пустой набор записей. Этот частично правильный результат не дает запрос из FAQ.

Совпадение результатов на основной базе является совершенно случайным. Так уж оказалось, что те производители, которые выпускают нужные по условию задачи ПК, выпускаю также и нужные ПК-блокноты.

Таким образом, несмотря на совпадение результатов на "видимой" базе, запрос не является правильным при любом совместимом со схемой состоянием БД.

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

SELECT maker, a.model a_m, b.model b_m, c.model c_m
   FROM product a, pc b, laptop c
   WHERE ((b.speed >= 750 AND c.speed >= 750)
      AND a.model = b.model)
      OR
      ((b.speed >= 750 AND c.speed >= 750)
      AND a.model = c.model)

А вот пара строк из результата:

Maker a_m b_m c_m
B 1121 1121 1752
A 1752 1121 1752

Как видно, модель 1121 (ПК) принадлежит производителю В, а модель 1752 (ПК-блокнот) - производителю А. Так что у нас нет никаких оснований считать, что оба эти производителя удовлетворяют условиям задачи.

Приведенные здесь примеры можно выполнить непосредственно на сайте, установив флажок "Без проверки" на странице с упражнениями на SELECT.

Перейти к решению задачи #23

На главную страницу

Print  Версия для печати


Использование любых материалов данного сайта возможно только
при условии обязательного размещения прямой ссылки на сайт
http://www.sqlbooks.ru
на каждой странице, где размещены используемые материалы.

 Начало   Статьи    Книги 
Рейтинг@Mail.ru Rambler's Top100 Alt Упражнения по SQL: обучение, тестирование, сертификация по языку SQL Copyright c 2002-2006. All rights reserved.