|
Программирование >> Исключение дубликатов строк
Еще раз рассмотрим таблицы Recipes и Recipe Classes. Для данного примера предположим, что нас интересуют только виды Salads (Салаты), Soups (Супы) и Main courses (Главные блюда). Вот запрос с использованием таблицы Recipe Classes, отфильтрованной в операторе SELECT, который является частью INNER JOIN: SQL SELECT RCFiltered.ClassName, R.RecipeTitle FROM (SELECT RecipeClassID, RecipeClassDescription AS ClassName FROM RecipeClasses AS RC WHERE RC.ClassName = Salads OR RC.ClassName = Soup OR RC.ClassName = Main Course) AS RCFiltered LEFT OUTER JOIN Recipes AS R ON RCFiltered.RecipeClassID = R.RecipeClassID Будьте осторожны при использовании оператора SELECT в условии FROM. В первую очередь, когда принимается решение заменить оператор SELECT на имя таблицы, обязательно нужно включить не только столбцы, которые должны присутствовать в окончательном результате, но также все связывающие столбцы, необходимые для выполнения JOIN. Именно поэтому во вложенном операторе присутствуют как RecipeClassID, так и RecipeClassDescription. Просто для шутки присвоим RecipeClassDescription псевдоним ClassName во вложенном операторе. В результате условие SELECT запрашивает ClassName, а не RecipeClassDescription. Условие ON ссылается теперь на корреляционное имя вложенного оператора SELECT - RCFiltered - вместо исходного имени таблицы или корреляционного имени, присвоенного таблице во вложенном операторе SELECT. Если данный запрос выполнить для реального примера базы данных Recipes, то получим одну строку с RecipeClassDescription для Soup со значением Null, возвращенным для RecipeTitle, потому что в этом примере базы данных рецепты супов отсутствуют. Также легко можно было бы построить оператор SELECT по таблице Recipes в правой части OUTER JOIN. Например, можно запросить все рецепты, содержащие слово beef (говядина) в своем заголовке: SQL SELECT RCFiltered.ClassName, R.RecipeTitle FROM (SELECT RecipeClassID, RecipeClassDescription AS ClassName FROM RecipeClasses AS RC WHERE RC.ClassName = Salads OR RC.ClassName = Soup OR RC.ClassName = Main Course) AS RCFiltered LEFT OUTER JOIN (SELECT Recipes.RecipeClassID, Recipes.RecipeTitle FROM Recipes WHERE Recipes.RecipeTitle LIKE XbeefX) AS R ON RCFiltered.RecipeClassID = R.RecipeClassID LEFT OUTER JOIN запрашивает все строки из набора результатов или таблицы, указанной в левой части JOIN, независимо от того, суш,ествуют ли строки, удов-летворяюш,ие условию, в правой части. Предыдуш,ий запрос не только возвраш,ает строку Soup со значением Null в RecipeTitle (поскольку в базе данных вообш,е отсутствуют рецепты супов), но также и строку Salad со значением Null. Можно было бы предположить, что в базе данных также отсутствуют и рецепты салатов, но фактически они там есть, только отсутствуют салаты с beef в заголовке рецепта! Внимание! Возможно, вы обратили внимание, что можно ввести полное условие поиска как часть условия ON в JOIN. Совершенно правильно, поэтому вполне законно по стандарту SQL решить приведенную выше задачу следуюш,им образом: SELECT Recipe Classes.RecipeClassDescription, Recipes.RecipeTitle FROM RecipeClasses LEFT OUTER JOIN Recipes ON Recipe Classes.RecipeClassID = Recipes.RecipeClassID AND (Recipe.Classes.RecipeClassDescription = Salads OR Recipe Classes.RecipeClassDescription = OR RecipeClasses.RecipeClassDescription = AND Recipes.RecipeTitle LIKE %beef% Soup Main Course) К сожалению, некоторые основные реализации SQL решают эту задачу неверно или вообш,е не воспринимают этот синтаксис! Поэтому рекомендуется всегда указывать в условии поиска условия ON только такие критерии, которые сравнивают столбцы из двух таблиц или наборов результатов. Если нужно отфильтровать строки из базовых таблиц, делайте это в отдельном условии поиска в условии WHERE во вложенном операторе SELECT. вложение условий JOIN в условия JOIN Хотя многие задачи можно решить, просто связывая две таблицы, очень часто требуется связать три, четыре или более таблиц, чтобы получить все данные, необходимые для решения запроса. Например, может потребоваться извлечь всю существенную информацию о рецептах - тип рецепта, название рецепта и все компоненты для него - в одном запросе. Зная, как использовать OUTER JOIN, можно также получить список всех видов рецептов - даже тех, для которых пока
......ME/WUREMENIS......!\ MeasureAmountID PK Measu rementDescriptton REClPEjNOREOrENTS RedpelD PK RecipeSeqNo PK IngredienUD FK MeasureAmounllD FK Amount Recipes Л >. >.. д > < > X r. .1 > < > X > -t Ч i Ф 4 t> 4 -+hf RecipelD PK I RecipeTitle RecipeClassID PK Pre pa ration I Nores H- ij 11 .iKinit ti !<.> i.> > i ф!и м ;4*; i.M4i > i*> i К1>* 1 ♦ *Ш*и >t<w i4- K*iV * Recipe Classes V , V . r ; > v Ч- r f - r f r J RecipeClassID PK \ RecipeClassDescription vj . Рис. 9.7. Таблицы из примера базы данных Recipes, необходимые для извлечения всей информации о рецептах еще не определено ни одного рецепта, и все детали рецептов и их компонентов. На рис. 9.7 представлены все таблицы, необходимые для ответа на данный запрос. Похоже, что нужны данные из пяти различных таблиц. Их можно получить путем построения более сложного условия FROM, вкладывая условия JOIN в условия JOIN. Фокус вот в чем: везде, где можно определить имя таблицы, можно также определить взятое в целом условие JOIN, заключенное в скобки. На рис. 9.8 представлен упрощенный вариант соединения двух таблиц (для образования простого также с корреляционными именами). iiiiiiiilii l-DIStlNCT :>::-i:;;.j.- имятаблицы Типтироваиное выражение LEFT RIGHT JOIN имятоблицы OUTER ON Условие поиска Рис. 9.8. Простая операция JOIN двух таблиц Для того чтобы добавить третью таблицу к этому соединению, просто поставьте открывающую скобку перед именем первой таблицы, добавьте закрывающую скобку после условия поиска, а затем добавьте еще одно JOIN, имя таблицы, ключевое слово ON и еще одно условие поиска. На рис. 9.9 показано, как это сделать.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |