Использование подзапроса или INNER JOIN

Пункт 2 задачи 2 этой лабораторной работы от команды Microsoft SQL Server выглядит следующим образом:

Задача 1: получить информацию о цене продукта

Каждый продукт AdventureWorks имеет стандартную себестоимость, обозначающую стоимость производства продукта, и знак list price, обозначающий рекомендуемую цену продажи продукта. Эти данные хранятся в таблице SalesLT.Product. Каждый раз, когда товар заказывается, в таблице actual unit price также записывается SalesLT.SalesOrderDetail, по которой он был продан. Вы должны использовать подзапросы для сравнения себестоимости и прейскурантных цен для каждого продукта с ценами за единицу, взимаемыми при каждой продаже.

  1. Получите продукты, прейскурантная цена которых выше средней цены за единицу.

    Получите идентификатор продукта, название и цену по прейскуранту для каждого продукта, цена которого превышает среднюю цену за единицу для всех проданных продуктов.

  2. Получите продукты с прейскурантной ценой 100 или более, которые были проданы менее чем за 100.

    Получите идентификатор продукта, имя и прейскурантную цену для каждого продукта, у которого прейскурантная цена равна 100 или более, а продукт был продан менее чем за 100.

Решение (представленное по той же ссылке выше) для вышеуказанной проблемы: они представили следующий запрос, который возвращает 7 записей:

 SELECT ProductID, Name, ListPrice
 FROM SalesLT.Product
 WHERE ProductID IN (SELECT ProductID
                     FROM SalesLT.SalesOrderDetail
                     WHERE UnitPrice < 100.00)
   AND ListPrice >= 100.00
 ORDER BY ProductID;
Идантификационный номер продукта Имя Список цен 810 Горные рули HL 120,27 813 Шоссейные рули HL 120,27 876 Багажник для прицепного устройства - 4 велосипеда 120 894 Задний переключатель 121,46 907 Задние тормоза 106,5 948 Передние тормоза 106,5 996 HL Нижний кронштейн 121,49

Но при тех же критериях поиска мой собственный следующий запрос возвращает 27 записей (показано ниже), где list prices >=100 и UnitPrice < 100:

Вопрос: Почему решение, предложенное Microsoft Lab, правильное, а то, что делаю я, неверно:

SELECT p.ProductID, p.Name, p.ListPrice, s.UnitPrice
FROM SalesLT.Product p
JOIN SalesLT.SalesOrderDetail s ON p.ProductID = s.ProductID  
WHERE p.ListPrice >= 100.00
  AND s.UnitPrice < 100.00
ORDER BY ProductID;
Идантификационный номер продукта Имя Список цен Цена за единицу товара 810 Горные рули HL 120,27 72.162 810 Горные рули HL 120,27 72.162 810 Горные рули HL 120,27 72.162 813 Шоссейные рули HL 120,27 72.162 813 Шоссейные рули HL 120,27 72.162 813 Шоссейные рули HL 120,27 72.162 876 Багажник для прицепного устройства - 4 велосипеда 120.00 72.00 876 Багажник для прицепного устройства - 4 велосипеда 120.00 72.00 876 Багажник для прицепного устройства - 4 велосипеда 120.00 72.00 876 Багажник для прицепного устройства - 4 велосипеда 120.00 72.00 876 Багажник для прицепного устройства - 4 велосипеда 120.00 72.00 876 Багажник для прицепного устройства - 4 велосипеда 120.00 72.00 876 Багажник для прицепного устройства - 4 велосипеда 120.00 72.00 876 Багажник для прицепного устройства - 4 велосипеда 120.00 72.00 894 Задний переключатель 121,46 72,876 894 Задний переключатель 121,46 72,876 907 Задние тормоза 106,50 63,90 948 Передние тормоза 106,50 63,90 948 Передние тормоза 106,50 63,90 948 Передние тормоза 106,50 63,90 948 Передние тормоза 106,50 63,90 948 Передние тормоза 106,50 63,90 948 Передние тормоза 106,50 63,90 948 Передние тормоза 106,50 63,90 996 HL Нижний кронштейн 121,49 72,894 996 HL Нижний кронштейн 121,49 72,894 996 HL Нижний кронштейн 121,49 72,894 996 HL Нижний кронштейн 121,49 72,894

в командном запросе легко уменьшить количество продуктов, а затем уменьшить их на ListPrice, ваши запросы должны добавить условия в предложение on.

nbk 04.08.2024 22:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Для начала давайте будем немного педантичны и учтем разницу между тем, что от вас просила задача, и тем, что вы сделали вместо этого. В задаче вам предлагалось использовать подвыборку с основным запросом выбора SalesLT.Product и запросом подвыборки SalesLT.SalesOrderDetail. Вместо того, чтобы выполнить задание, вы сделали join. Технически вы также можете достичь цели задачи с помощью join, но вам нужно следовать инструкциям и, если вас просят использовать подзапрос, сделайте это.

Во-вторых, логическая ошибка, которую вы допустили, заключается в том, что когда вы присоединяетесь SalesLt.Product к SalesLT.SalesOrderDetail, вы присоединяетесь ко всем совпадениям, поэтому если у вас есть товар, который был продан 8 раз, то вы получите 8 пар и, следовательно, у вас будет 8 записей, соответствующих этот продукт вместо 1 (см., например, ProductID 876), который был бы результатом, если бы вы следовали инструкции и использовали подзапрос. Но чтобы добиться того же с помощью join, вы можете использовать group by, то есть объединить несколько кортежей товаров и продаж в отдельные записи, ровно по одной записи для каждого продукта, имеющего одно совпадение:

SELECT p.ProductID, p.Name, p.ListPrice
FROM SalesLT.Product p
JOIN SalesLT.SalesOrderDetail s ON p.ProductID = s.ProductID  
WHERE p.ListPrice >= 100.00
  AND s.UnitPrice < 100.00
GROUP BY p.ProductID, p.Name, p.ListPrice
ORDER BY ProductID;

В-третьих, ваш join и его подвыбор не оптимальны, поскольку они будут искать все пары, а не один пример. EXISTS ищет одно совпадение в подвыборке и, если совпадение найдено, прекращает поиск нового, тогда как IN находит ВСЕ совпадения и, следовательно, занимает больше времени, и в нашем случае нас интересует только EXISTS, поэтому:

 SELECT ProductID, Name, ListPrice
 FROM SalesLT.Product
 WHERE EXISTS (SELECT SalesLT.SalesOrderDetail.ProductID
               FROM SalesLT.SalesOrderDetail
               WHERE UnitPrice < 100.00 AND SalesLT.SalesOrderDetail.ProductID = SalesLT.Product.ProductID)
   AND ListPrice >= 100.00
 ORDER BY ProductID;

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

 SELECT ProductID, Name, ListPrice
 FROM SalesLT.Product
 WHERE ListPrice > (SELECT AVG(UnitPrice)
                    FROM SalesLT.SalesOrderDetail
                    WHERE SalesLT.Product.ProductID = SalesLT.SalesOrderDetail.ProductID)
ORDER BY ProductID;

Хорошее объяснение - конкретно по IN Vs. СУЩЕСТВУЕТ. Я кое-чему научился.

nam 05.08.2024 02:17

@nam рад помочь!

Lajos Arpad 05.08.2024 02:23

Другие вопросы по теме