2015-03-12 2 views
2

3 таблицы: Поставщики (с.и.д., SNAME, адрес), частей (ИДП, PNAME, цвет), каталог (SID, PID, стоимость)Найти МОРАГ поставщиков, которые поставляют каждую часть

Ответ на этот вопрос найти все поставщики, которые поставляют каждую деталь:

SELECT C.sid 
    FROM Catalog C 
    WHERE NOT EXISTS (
    SELECT P.pid 
     FROM Parts P 
     WHERE NOT EXISTS (
     SELECT C1.sid 
      FROM Catalog C1 
      WHERE C1.sid = C.sid 
      AND C1.pid = P.pid 
     ) 
    ) 

Может ли кто-нибудь объяснить мне этот ответ? Я просто немного потерян!

Я слышал, что объясняется как «Найти поставщиков таким образом, что не существует часть, которую они не продают», но я изо всех сил, чтобы увидеть, как

SELECT C1.sid 
      FROM Catalog C1 
      WHERE C1.sid = C.sid 
      AND C1.pid = P.pid 
     ) 

выполняет это.

Так что, если у меня есть таблица каталога

Джеймс | Молот

James | Anvil

James | Ключ

Генрих | Молот

Leroy | Наковальня

Часть Таблица

Молот

Наковальня

ключ

Затем после внутреннего пункта, что возвращается именно?

Факс:

James | Молот

James | Anvil

James | Ключ

Генрих | Молот

Leroy | Наковальня

, а затем НЕ СУЩЕСТВУЕТ делает

Джеймс | -

Генрих | Наковальня, гаечный ключ

Leroy | Молот, гаечный ключ?

Как таблица компонентов вычитает эти значения? Извините, если эти вопросы не слишком ясны, я все еще новичок в SQL.

+0

Что такое РСУБД, вы используете? –

+0

Извините, я не уверен, что понимаю этот вопрос. Вы имеете в виду SQL? – tryingtolearn

+0

Нет, какая у вас БД? MSSQL или MySQL или любой другой БД? –

ответ

5

Это двойной вложенный запрос NOT EXISTS (на самом деле это не то, что я обычно видел), и он используется специально для ответа на этот тип вопросов, т. Е. «Есть ли x true для всех y?"

Here's MySQL's page on EXISTS and NOT EXISTS, в котором упоминается этот метод специально.

во-первых, в сокровенной SELECT запросе, вы выбираете детали, возит каждый магазин. Затем, с первым NOT EXISTS пункта, вы выбираете детали, которые не выполняются по каждому магазину. И, наконец, во внешнем NOT EXISTS пункте, вы выбираете магазины, возвращаемые пустой набор для внутреннего NOT EXISTS пункта означает, что они несут каждую часть.

Here is a SQLFiddle этого запроса в действии.

Предупреждающее слово: если вы работаете с SQL, всегда хорошо думать и работать в наборах, и мышление в линейных терминах, как то, что должно следовать, может быстро вызвать вас. Не делайте это привычкой!

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

Таким образом, принимая данные в скрипке в качестве примера, мы имеем:

suppliers: 
sid, name 
9, 'AAA' 
8, 'BBB' 
7, 'CCC' 

parts: 
pid, name 
1, 'wood' 
2, 'stone' 
3, 'paper' 

catalog: 
cid, pid, sid 
1,1,9 
2,2,9 
3,1,8 
4,1,7 
5,2,7 
6,3,7 

Так что с этими данными, AAA несет дерево и камень, ГЭБ только несет дрова, и CCC несет дерево, камень, и бумага.

Теперь давайте проверим запрос по строкам. Мы выбираем из suppliers, и мы решаем, какие строки включать в результирующий набор, поэтому начните с первой строки в suppliers: 9,'AAA'. Мы будем называть эту строку S временно. Мы включим эту строку только в том случае, если во внутреннем наборе результатов нет ничего, поэтому давайте взглянем на это.

suppliers: 
sid, name 
S => 9, 'AAA' 
    8, 'BBB' 
    7, 'CCC' 

Этот набор результатов выбора из parts, и мы собираемся пройти через это ряд за рядом. S по-прежнему равен 9,'AAA', пока мы это делаем. Поэтому начните с первой строки в parts: 1,'wood'. Назовем этот ряд P. Мы включим эту строку только в этот первый внутренний результирующий набор, если на следующем уровне набора результатов ничего не будет, поэтому давайте переместимся туда. Помните, что S = 9,'AAA' и P = 1,'wood'.

suppliers: 
sid, name 
S => 9, 'AAA' 
    8, 'BBB' 
    7, 'CCC' 

parts: 
pid, name 
P => 1, 'wood' 
    2, 'stone' 
    3, 'paper' 

Этот самый внутренний запрос выбирается из «каталога». Мы ищем любую строку, назовем ее C, в catalog, где C.sid равно S.sid И C.pid равно P.pid. Это означает, что текущий поставщик несет часть. Нам нужны детали, которые текущий поставщик НЕ переносит, поэтому мы инвертируем результирующий набор. Мы знаем, что sid S равен 9, и мы знаем, что pid P равен 1. Есть ли какие-либо строки в C, которые соответствуют этому? Самая первая строка в C соответствует этому, поэтому мы знаем, что этот набор результатов не пуст.

suppliers: 
sid, name 
S => 9, 'AAA' 
    8, 'BBB' 
    7, 'CCC' 

parts: 
pid, name 
P => 1, 'wood' 
    2, 'stone' 
    3, 'paper' 

catalog: 
cid, pid, sid 
C => 1,1,9 --Match found! Don't include P in outer result set 
    2,2,9 
    3,1,8 
    4,1,7 
    5,2,7 
    6,3,7 

Теперь вернитесь к следующей внешней петле. Внутренний результирующий набор не был пустым, поэтому мы знаем, что 1,'wood не будет частью результирующего набора этого цикла. Поэтому мы переходим к следующему ряду в parts, 2,'stone'.Мы обновляем значение P, чтобы сравнять эту строку. Следует ли включить эту строку в результирующий набор? Мы снова должны выполнить внутренний запрос с нашим новым значением для P (S все еще не изменилось). Поэтому мы ищем любые строки в catalog с sid равными 9 и pid, равными 2. Вторая строка соответствует, поэтому существует результирующий набор.

suppliers: 
sid, name 
S => 9, 'AAA' 
    8, 'BBB' 
    7, 'CCC' 

parts: 
pid, name 
    1, 'wood' 
P => 2, 'stone' 
    3, 'paper' 

catalog: 
cid, pid, sid 
    1,1,9 
C => 2,2,9 --Match found! Don't include P in outer result set 
    3,1,8 
    4,1,7 
    5,2,7 
    6,3,7 

Вернитесь к следующей внешней петле. Внутренний результирующий набор не был пустым, поэтому 2,'stone' не будет частью результирующего набора этого цикла.

Когда мы снова пройти через все это 3,'paper', мы находим, что нет ни одной строки в catalog, которые имеют sid = 9 и pid = 3. Самый внутренний набор результатов пуст, поэтому мы знаем, что это значение должно быть P в следующем крайнем цикле.

suppliers: 
sid, name 
S => 9, 'AAA' 
    8, 'BBB' 
    7, 'CCC' 

parts: 
pid, name 
    1, 'wood' 
    2, 'stone' 
P => 3, 'paper' 

catalog: 
cid, pid, sid 
    1,1,9 
    2,2,9 
    3,1,8 
    4,1,7 
    5,2,7 
    6,3,7 
C => --No match found, include P in outer result set 

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

Таким образом, мы переходим к следующей строке в suppliers и начать весь процесс заново:

suppliers: 
sid, name 
    9, 'AAA' 
S => 8, 'BBB' 
    7, 'CCC' 

После того, как мы получаем S = 7,'CCC' мы будем проходить через все эти петли, и матч будет найден в внутренний цикл для каждого значения P, которое поставляется, что означает, что этот второй цикл будет иметь пустой набор. Мы не смогли найти какие-либо детали, которые поставщик не несет, поэтому в набор результатов добавляется значение S, то есть они несут все!

+0

Я понимаю. Можете ли вы объяснить, что означает конечная часть, которую я выделил? Как (C1.sid = C.id AND C1.pid = P.pid) отличается от (C.pid = P.pid). Кажется, что это совсем другое, но я не вижу, как это сделать. – tryingtolearn

+0

Что-то получилось немного, см. Мой расширенный ответ. –

+0

Думаю, я смогу немного поучиться. Однако в частях, где НЕ СУЩЕСТВУЕТ, не должен ли самый внутренний SELECT быть атрибутом, который разделяет таблица Parts? – tryingtolearn

Смежные вопросы