|
Программирование >> Программирование баз данных
Выполнение этого запроса приводит к получению правильных результатов: OrderDate ProductID 2001-07-01 00:00:00.000 707 2001-07-01 00:00:00.000 708 2001-07-01 00:00:00.000 709 2001-07-01 00:00:00.000 776 2001-07-01 00:00:00.000 777 2001-07-01 00:00:00.000 778 (47 row(s) affected) Но предположим для примера, что в данной системе регулярно удаляются устаревшие данные, однако остается потребность в поиске ответа на тот же вопрос для составления автоматизированного отчета. Итак, перед нами стоит задача автоматизации работы, поскольку нельзя предусмотреть вьшолнение запроса для определения того, за какую первую дату имеются данные в системе, после чего вручную включить полученную дату в следующий запрос. Решение указанной задачи может состоять в том, чтобы добавить переменную (применение переменных будет рассматриваться в главе 11) и сделать ее частью пакета: DECLARE ©FirstDate smalldatetime SELECT ©FirstDate = MIN(OrderDate) FROM Sales.SalesOrderHeader SELECT DISTINCT soh.OrderDate, sod.ProductID FROM Sales.SalesOrderHeader soh JOIN Sales.SalesOrderDetail sod ON soh.SalesOrderlD = sod.SalesOrderlD WHERE soh.OrderDate = ©FirstDate Очевидно, что такая конструкция является применимой (в этом можно убедиться, проверив, будут ли получены те же результаты), но фактически можно еще больше упростить структуру запроса, поместив все используемые конструкции в один оператор: SELECT DISTINCT о.OrderDate, od.ProductID FROM Sales.SalesOrderHeader soh JOIN Sales.SalesOrderDetail sod ON soh.SalesOrderlD = sod.SalesOrderlD WHERE soh.OrderDate = (SELECT MIN(OrderDate) FROM Sales.SalesOrderHeader) ICaK оказалось, решение является простым и удобным. С помощью внутреннего запроса, (SELECT MIN. . .), осуществляется выборка единственного значения, предназначенного для использования во внешнем запросе. Кроме того, поскольку в качестве операции сравнения задана операция сравнения на равенство, необходимо обеспечить, чтобы внутренний запрос возвращал значение только единственного поля одной строки, поскольку в противном случае возникает ошибка этапа прогона. Запросы с вложенными подзапросами, которые возвращают несколько значений По-видимому, наиболее широко применяются такие подзапросы, в которьгх в той или иной форме осуществляется выборка перечня допустимьгх значений, которые затем используются в запросе в качестве критериев. А в данном случае необходимо составить список всех служащих, которые подали заявление о переходе на другую работу в той же компании. Список таких заявителей сохраняется в таблице HumanResrou-ces. JobCandidate, поэтому необходимо составить список идентификаторов EmployeelD, к которым относится одна из строк в таблице кандидатов на получение другой работы. Безусловно, сам действительный список всех служащих находится в таблице HumanResources . Employee. Кроме того, для получения таких данных, как имена служащих, будет использоваться таблица Person. Contact. Предположим, что вначале для решения этой задачи применяется следующий запрос: USE AdventureWorks SELECT е.EmployeelD, FirstName, LastName FROM HumanResources.Employee e JOIN Person.Contact с ON e.ContactID = e.ContactID WHERE e.EmployeelD IN (SELECT DISTINCT EmployeelD FROM HumanResources.JobCandidate) Этот запрос возвращает только две строки: EmployeelD FirstName LastName 41 Peng Wu 268 Stephen Jiang (2 row(s) affected) И действительно, запросы с вложенными подзапросами, подобные приведенному выше, почти всегда можно отнести к категории таких запросов, которые можно осуществить с использованием внутреннего соединения, а не вложенного оператора SELECT. Например, такие же результаты, как и в предыдущем запросе с вложенным подзапросом, можно получить после вызова на выполнение следующего простого оператора с конструкцией JOIN: USE AdventureWorks SELECT e.EmployeelD, FirstName, LastName FROM HumanResources.Employee e JOIN Person.Contact с ON e.ContactID = e.ContactID JOIN HumanResources.JobCandidate jc ON e.EmployeelD = jс.EmployeelD В целях обеспечения высокой производительности следует неизменно прибегать к использованию метода, основанного на соединении, если нет каких-либо весомых аргументов в пользу применения запроса с вложенным оператором SELECT. Дополнительная информация на эту тему приведена в конце настоящей главы. Использование запроса с вложенным оператором select для поиска висячих строк Вложенный оператор SELECT такого типа, который рассматривается в данном разделе, почти идентичен приведенному в предьщущем примере, за исключением того, что в нем используется также операция NOT. Переходя к сравнению с синтаксической конструкцией соединения, можно отметить, что из-за этого различия применяемый оператор с вложенным подзапросом начинает в большей степени напоминать внешнее соединение, а не внутреннее. Эта задача в большей степени относится к той категории задач, в которых требуется найти недостающую информацию. Во многих случаях необходимость в этом возникает, если, допустим, имеются строки расшифровки заказа, для которых отсутствуют родительские строки в таблице заголовка (безусловно, такая ситуация не может возникнуть в базе данных AdventureWorks благодаря наличию ограничения внешнего ключа, но есть и такие базы данных, в которых подобные случаи имеют место). В рассматриваемом примере будут внесены изменения в сценарий, чтобы он позволял узнать, какие служащие не подали заявление о переходе на другую работу в компании. Чтобы узнать, как поступить в этом случае, мы можем исходить из того, что речь идет об отрицании, не , иными словами, в запрос необходимо ввести операцию NOT (но следует учитывать, что может возникнуть неблагоприятный частный случай, о котором речь пойдет в следующем примечании): USE AdventureWorks SELECT е.EmployeelD, FirstName, LastName FROM HumanResources.Employee e JOIN Person.Contact с ON e.ContactID = e.ContactID WHEKE e.EmployeelD NOT IN (SELECT DISTINCT EmployeelD FROM HumanRe s ou r с e s.JobСandidate WHERE EmployeelD IS NOT NULL) После вызова этого оператора на вьшолнение, разумеется, будет получен крупный результирующий набор (в который войдут данные обо всех служащих, кроме тех двух, что рассматривались в предьщущем примере). Как всегда, при выполнении операторов проверки применительно к множествам, которые могут содержать NULL-значения, необходимо соблюдать осторожность. Дело в том, что применение операций сравнения к NULL-значениям всегда приводят к получению NULL-значений. В описанном выше случае таблица JobCandidate включает строки, в которых столбец EmployeelD содержит NULL-значения. Если бы в подзапросе был разрешен возврат NULL-значений, то после вьшолнения операции сравнения с помощью ключевьгх слов NOT IN каждая строка во внешнем запросе принимала бы значение False, что привело бы к получению пустого списка (рекомендуем провести эксперименты с тем и другим вариантом запроса, чтобы понять, в чем состоит разница). Операции any, some и all До сих пор рассматривался только такой способ организации запроса, в котором осуществлялся поиск элемента в списке с помощью операции IN, иными словами, в списке необходимо было найти по крайней мере одно значение, точно соответствующее искомому. Но, к сожалению, на этом не исчерпываются все задачи, с которыми приходится сталкиваться в повседневной работе. Например, иногда возникает необходимость провести сравнение с применением операции, отличной от той, которая помогает находить лишь точное соответствие, т.е. операции, которая отнюдь не эквивалентна проверке на равенство (операции =). Иными словами, чтобы иметь возможность составлять достаточно разносторонние запросы, необходимо иметь в своем распоряжении достаточно широкий перечень операций сравнения. В СУБД SQL Server такая возможность действительно предоставляется. Однако часто требуется также обеспечить выборку данных по условию. В частности, может возникнуть необходимость определить, согласуется ли каждое значение в списке с какими-либо данными. И в этом случае СУБД SQL Server предоставляет необходимые программные конструкции.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |