2016-05-28 2 views
0

Это упражнение из Викиучебников, #6Как работает этот SQL-запрос?

Схема таблицы enter image description here

Возникает вопрос:

Для каждой части, найти самое дорогое предложение этой части и включают имя кусок , имя поставщика и цену (обратите внимание, что могут быть два провайдера, которые поставляют один и тот же товар по самой дорогой цене).

Решение:

SELECT Pieces.Name, Providers.Name, Price 
    FROM Pieces INNER JOIN Provides ON Pieces.Code = Piece 
       INNER JOIN Providers ON Providers.Code = Provider 
    WHERE Price = 
    (
    SELECT MAX(Price) FROM Provides 
    WHERE Piece = Pieces.Code 
    ); 

Я не понимаю подзапросов часть. Я думаю, что типичный способ найти максимальную цену является

SELECT MAX(Price) FROM Provides 
group by piece; 

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

SELECT MAX(Price) FROM Provides, pieces where provides.piece=pieces.code; 

Он просто возвращает самое большое число, я не могу понять, почему он может «группировать» и возвращать правильные строки.

+0

Вы можете подумать об этом, что у вас есть одна «группа» строк в подзапросе - все строки, удовлетворяющие условиям из предложения where. И это построено с использованием «коррелированного подзапроса», если вы хотите узнать название этого метода для исследовательских целей. – michaJlS

+0

@michaJlS Спасибо, не знаю, это особый трюк. – Jacob

ответ

2

Хотя Томас действительно предлагает гораздо более простое решение, вернемся к исходному вопросу, ПОЧЕМУ он работает.

SELECT Pieces.Name, Providers.Name, Price 
    FROM Pieces INNER JOIN Provides ON Pieces.Code = Piece 
       INNER JOIN Providers ON Providers.Code = Provider 
    WHERE Price = 
    (
    SELECT MAX(Price) FROM Provides 
    WHERE Piece = Pieces.Code 
    ); 

Во-первых, я ненавижу работать с коррелированными подзапросами, как в этом ответе. Коррелированный подзапрос - это тот, который подзапрос обрабатывается один раз для записи EACH. Обратите внимание, что внешняя часть запроса предоставляет ссылку на таблицу «Pieces». Поэтому внутренний запрос говорит из таблицы «PROVIDES», дайте мне максимальную цену для текущего значения «Pieces.code». После этого это простое соединение с другими таблицами, чтобы захватить детали и детали поставщика.

Мое личное предпочтение состоит в том, чтобы сделать предварительный агрегатный подзапрос ONCE в таблице «Обеспечивает» всеми кодами с собственной группой. Это запускает запрос один раз, сгруппированный, поэтому есть только одна запись для соответствующего кода. Чаще всего вы увидите такие запросы, чтобы предотвратить большие накладные расходы. Кроме того, хорошо работать с именами псевдонимов, особенно если вы имеете дело с использованием псевдонима.

from LongTableNamesInYourDatabase LTN 

И всякий раз, когда вы работаете с несколькими таблицами, всегда стараемся обеспечить table.column или alias.column, так что другие пытаются помочь вам в будущем знать, где конкретный столбец из и не только гадать.

SELECT 
     P.Name, 
     Prov.Name, 
     MaxByPiece.MaxPrice 
    FROM 
     (SELECT 
       Pr1.Piece, 
       MAX(Pr1.Price) as MaxPrice 
      FROM 
       Provides Pr1 
      group by 
       Pr1.Piece) as MaxByPiece 
     JOIN Provides Pr2 on MaxByPiece.Piece = Pr2.Piece AND MaxByPiece.MaxPrice = Pr2.Price 
      JOIN Pieces P on Pr2.Piece = P.Code 
      JOIN Providers Prov on Pr2.Provider = Prov.Code 

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

Первый запрос из предложения ничего не делает, кроме как получить максимальную цену за любую часть, и я использую псевдоним Pr1, чтобы отличить его от следующего соединения. Присоединение после этого - это предоставление, поэтому мы можем найти ВСЕ Пьесы по этой цене. Помните, что вопрос требовал ВСЕ ПРОГНОЗЫ по этой максимальной цене. Итак, теперь у меня есть записи, которые имеют максимальную цену за штуку и поставщика. Поэтому я заканчиваю, присоединяясь к тем таблицам поиска, чтобы получить имена

+0

Спасибо за подробности и предложения. – Jacob

1

Я не могу понять, почему это может «группа» и вернуть правильные строки

Используя группу и MAX Агрегатная функция также рабочий раствор.

Это:

SELECT Pieces.Name, Providers.Name, MAX(Price) 
    FROM Pieces INNER JOIN Provides ON Pieces.Code = Piece 
       INNER JOIN Providers ON Providers.Code = Provider 
GROUP BY Piece 

будет работать на MySQL и возвращать те же результаты.

Коррелированное решение подзапроса в основном обеспечивает одно и то же, но выражается по-разному. Однако «мое» решение не будет работать на многих РСУБД, поскольку столбцы в SELEcT отличаются от столбцов в GROUP BY. Это разрешено в MySQL.

Возможно, они предпочитают указывать решение подзапроса, поскольку оно является стандартным. Это немного странно, так как в реальной ситуации разработчик наиболее часто выбирает подход GROUP BY, а на других СУБД будут добавлять столбцы, необходимые для его работы.

+0

Спасибо, это полезно. Особенно разъяснение. – Jacob

+0

Нет, ваш запрос неправильный. Вы группируете по частям, так что вы получаете все продавцы штук по цене. Вы берете максимальную цену ('MAX (Price)' в предложении SELECT') и один из поставщиков ('Provider' в предложении' ON'). Это не обязательно поставщик, предлагающий максимальную цену. –

+0

@thorstenlettner Право Я забыл эту часть, я также добавил несколько дополнительных сведений. –

1

Предложение WHERE работает так: со всеми строками, полученными из FROM (то есть комбинации Pieces-Provides-Providers в вашем случае) проверьте, соответствуют ли условия в WHERE; держите строку только в том случае, если это так.

WHERE Price = 
(
    SELECT MAX(Price) FROM Provides 
    WHERE Piece = Pieces.Code 
) 

Здесь вы берете строку шт-Обеспечивают-провайдеров, использовать его Pieces.Code и получить все матчи от Provides. Тогда вы берете от них максимальную цену. Это значение сравнивается с ценой вашей серии Pieces-Provides-Providers. Если это то же самое (т. Е. Если ваша объединенная строка имеет максимальную цену для кода штук), вы сохраните эту строку.

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