Мартин Грубер - Понимание SQL (991940), страница 23
Текст из файла (страница 23)
Мы просто показывали вывод сначала из одногозапроса, а затем из другого. Конечно, вы не можете полагаться на вывод, приходящийв произвольном порядке. Мы как раз сделаем так, чтобы этот способ для выполненияпримеров был более простым. Вы можете использовать предложение ORDER BYчтобы упорядочить вывод из объединения, точно так же как это делается в индивидуальных запросах. Давайте пересмотрим наш последний пример чтобы упорядочитьимена с помощью их порядковых номеров. Это может внести противоречие, такое какповторение имени Peel в последней команде, как вы сможете увидеть из вывода показанного в Рисунке 14.5.SELECT a.snum, sname, onum, 'Highest on', odateFROM Salespeople a, Orders bWHERE a.snum = b.snum AND b.amt = ( SELECT MAX (amt)FROM Orders cWHERE c.odate = b.odate )UNIONSELECT a.snum, sname, onum, ' Lowest on', odateFROM Salespeople a, Orders bWHEREa.snum = b.snum AND b.amt = ( SELECT MIN (amt)FROM Orders cWHERE c.odate = b.odate )ORDER BY 3;=============== SQL Execution Log ============| ( SELECT min (amt)|| FROM Orders c|| WHERE c.odate = b.odate)|| ORDER BY 3;|| ============================================= |||| ----- ------- ------ ---------- ----------- || 1007 Rifkin3001Lowest on 10/03/1990 || 1002 Serres3005Highest on 10/03/1990 || 1002 Serres3007Lowest on 10/04/1990 || 1001 Peel3008Highest on 10/05/1990 || 1001 Peel3008Lowest on 10/05/1990 || 1003 Axelrod 3009Highest on 10/04/1990 || 1002 Serres3010Lowest on 10/06/1990 || 1001 Peel3011Highest on 10/06/1990 |===============================================Рисунок 14.5: Формирование объединения с использованием ORDER BYПока ORDER BY используется по умолчанию, мы не должны его указывать.
Мыможем упорядочить наш вывод с помощью нескольких полей, одно внутри другого иуказать ASC или DESC для каждого, точно также как мы делали это для одиночныхзапросов. Заметьте, что номер 3 в предложении ORDER BY указывает какой столбециз предложения SELECT будет упорядочен. Так как столбцы объединения — этостолбцы вывода, они не имеют имен, и следовательно, должны определяться по номеру. Этот номер указывает на их место среди других столбцов вывода. (СмотритеГлаву 7, обсуждающую столбцы вывода.)ВНЕШНЕЕ ОБЪЕДИНЕНИЕОперация, которая бывает часто полезна — это объединение из двух запросов,в котором второй запрос выбирает строки, исключенные первым.
Наиболее часто, выбудете делать это, так чтобы не исключать строки, которые не удовлетворили предикату при объединении таблиц. Это называется внешним обьединением.Предположим что некоторые из ваших заказчиков еще не были назначены кпродавцам. Вы можете захотеть увидеть имена и города всех ваших заказчиков, сименами их продавцов, не учитывая тех, кто еще не был назначен. Вы можете достичь этого, формируя объединение из двух запросов, один из которых выполняет обьединение, а другой выбирает заказчиков с пустыми (NULL) значениями поля snum.Этот последний запрос должен вставлять пробелы в поля, соответствующие полюsname в первом запросе.Как и раньше, вы можете вставлять текстовые строки в ваш вывод, чтобы идентифицировать запрос который вывел данную строку.
Использование этой методики вовнешнем обьединении дает возможность использовать предикаты для классификации, а не для исключения. Мы использовали пример нахождения продавцов с заказчиками размещенными в их городах и раньше. Однако вместо просто выбора толькоэтих строк, вы возможно захотите чтобы ваш вывод перечислял всех продавцов, иуказывал тех, кто не имел заказчиков в их городах, и кто имел.
Следующий запрос,чей вывод показывается в Рисунке 14.6, выполнит это:SELECT Salespeople.snum, sname, cname, commFROM Salespeople, CustomersWHERE Salespeople.city = Customers.cityUNIONSELECT snum, sname, ' NO MATCH', commFROM SalespeopleWHERE NOT city = ANY ( SELECT cityFROM Customers )ORDER BY 2 DESC;=============== SQL Execution Log ============| FROM Salespeople|| WHERE NOT city = ANY ( SELECT city||FROM Customers )|| ORDER BY 2 DESC;|| ============================================= |||| ----- ------- -------------------|| 1002 SerresCisneros0.1300|| 1002 SerresLiu0.1300|| 1007 RifkinNO MATCH0.1500|| 1001 PeelClemens0.1200|| 1001 PeelHoffman0.1200|| 1004 MotikaClemens0.1100|| 1004 MotikaHoffman0.1100|| 1003 Axelrod NO MATCH0.1000|===============================================Рисунок 14.6: Внешнее обьединениеСтрока 'NO MATCH' была дополнена пробелами, чтобы получить совпадениеполя cname по длине (это не обязательно во всех реализациях SQL).
Второй запросвыбирает даже те строки, которые исключил первый. Вы можете также добавить комментарий или выражение к вашему запросу, в виде дополнительного поля. Если высделаете это, вы будете должны добавить некоторый дополнительный комментарийили выражение в той же самой позиции среди выбранных полей, для каждого запросав операции объединения.
Совместимость UNION предотвращает вас от добавлениядополнительного поля для первого запроса, но не для второго. Имеется запрос, который добавляет строки к выбранным полям, и указывает, совпадает ли данный продавец с его заказчиком в его городе:SELECT a.snum, sname, a.city, ' MATCHED 'FROM Salespeople a, Customers bWHERE a.city = b.cityUNIONSELECT snum, sname, city, 'NO MATCH'FROM SalespeopleWHERE NOT city = ANY ( SELECT cityFROM Customers )ORDER BY 2 DESC;Рисунок 14.7 показывает вывод этого запроса.=============== SQL Execution Log ============| WHERE a.city = b.city|| UNION|| SELECT snum,sname,city, 'NO MATCH'|| FROM Salespeople|| WHERE NOT city = ANYate)|| ( SELECT city|| FROM Customers)|| ORDER BY 2 DESC;|| ============================================= |||| ----- ------------------ --------|| 1002 SerresSan JoseMATCHED|| 1007 RifkinBarselonaNO MATCH|| 1001 PeelLondonMATCHED|| 1004 MotikaLondonMATCHED|| 1003 AxelrodNew YorkNO MATCH|===============================================Рисунок 14.7: Внешнее обьединение с полем коментарияЭто не полное внешнее объединение, так как оно включает только несовпадающие поля одной из объединяемых таблиц.
Полное внешнеее объединение должновключать всех заказчиков, имеющих и не имеющих продавцов в их городах. Такое условие будет более полным, как вы это сможете увидеть (вывод следующего запросапоказан на Рисунке 14.8):SELECT snum, city, 'SALESPERSON — MATCH'FROM SalespeopleWHERE NOT city = ANY (SELECT cityFROM Customers)UNIONSELECT snum, city, 'SALESPERSON — NO MATCH'FROM SalespeopleWHERE NOT city = ANY (SELECT cityFROM Customers))UNIONSELECT cnum, city, 'CUSTOMER — MATCHED'FROM CustomersWHERE city = ANY (SELECT cityFROM Salespeople)UNIONSELECT cnum, city, 'CUSTOMER — NO MATCH'FROM CustomersWHERE NOT city = ANY (SELECT cityFROM Salespeople))ORDER BY 2 DESC;================= SQL Execution Log =============| FROM Salespeople)|| ORDER BY 2 DESC;|| ================================================ |||| ---------------------------------|| 2003San JoseCUSTOMER—MATCHED|| 2008San JoseCUSTOMER—MATCHED|| 2002RomeCUSTOMER—NO MATCH|| 2007RomeCUSTOMER—NO MATCH|| 1003New YorkSALESPERSON —MATCHED|| 1003New YorkSALESPERSON —NO MATCH|| 2001LondonCUSTOMER—MATCHED|| 2006LondonCUSTOMER—MATCHED|| 2004BerlinCUSTOMER—NO MATCH|| 1007BarcelonaSALESPERSON —MATCHED|| 1007BarcelonaSALESPERSON —NO MATCH|==================================================Рисунок 14.8: Полное внешнее обьединение(Понятно, что эта формула, использующая ANY, — эквивалентна обьединению впредыдущем примере.)Сокращенное внешнее обьединение, с которого мы начинали, используется чаще чем этот последний пример.
Этот пример, однако, имеет другой смысл. Всякийраз, когда вы выполняете объединение более чем двух запросов, вы можете использовать круглые скобки чтобы определить порядок оценки. Другими словами, вместопросто —query X UNION query Y UNION query Z;вы должны указать, или( query X UNION query Y )UNION query Z;илиquery X UNION ( query Y UNION query Z );Это потому, что UNION и UNION ALL могут быть скомбинированны, чтобы удалять одни дубликаты, не удаляя других. Предложение( query X UNION ALL query Y )UNION query Z;не обязательно воспроизведет те же результаты что предложениеquery X UNION ALL( query Y UNION query Z );если двойные строки в нем, будут удалены.РЕЗЮМЕТеперь вы знаете, как использовать предложение UNION, которое дает возможность объединять любое число запросов в единое тело вывода.