Знакомство с инструкцией SELECT
Transact-SQL или T-SQL — разновидность языка SQL стандарта ANSI, используемого продуктами и службами Microsoft SQL. Он аналогичен стандартному SQL. Большая часть внимания здесь будет уделяться инструкции SELECT, которая обладает большей частью возможностей и вариаций любой инструкции DML.
Начнем с подробного обзора того, как обрабатывается инструкция SELECT. Порядок содержимого в инструкции SELECT не является порядком, в котором она обрабатывается ядром СУБД SQL Server.
Обратите внимание на следующий запрос:
SELECT OrderDate, COUNT(OrderID) AS Orders
FROM Sales.SalesOrder
WHERE Status = 'Shipped'
GROUP BY OrderDate
HAVING COUNT(OrderID) > 1
ORDER BY OrderDate DESC;
Запрос содержит инструкцию SELECT, состоящую из нескольких предложений, каждое из которых определяет некую операцию, которая применяется к получаемым данным. Прежде чем переходить к порядку выполнения операций, давайте кратко рассмотрим, что делает этот запрос, хотя подробнее о различных предложениях можно будет узнать далее в этом модуле.
Предложение SELECT возвращает столбец OrderDate и количество значений OrderID, которому присваивается имя (или псевдоним) Orders:
SELECT OrderDate, COUNT(OrderID) AS Orders
Предложение FROM определяет, какая таблица является источником строк для запроса; в данном случае это таблица Sales.SalesOrder:
FROM Sales.SalesOrder
Предложение WHERE фильтрует строки из результатов, сохраняя только те строки, которые соответствуют указанному условию; в данном случае это заказы с состоянием "shipped":
WHERE Status = 'Shipped'
Предложение GROUP BY принимает строки, удовлетворяющие условиям фильтра, и группирует их по параметру OrderDate; в результате все строки с одинаковым значением OrderDate рассматриваются как одна групп, и для каждой группы возвращается одна строка:
GROUP BY OrderDate
После формирования групп предложение HAVING фильтрует группы на основе собственного предиката. В результаты будут включаться только даты с более чем одним заказом:
HAVING COUNT(OrderID) > 1
Для предварительного просмотра этого запроса, последним предложением которого будет ORDER BY, которое сортирует выходные данные в порядке убывания согласно OrderDate:
ORDER BY OrderDate DESC;
Теперь, когда вы видели, что делает каждое предложение, давайте посмотрим на порядок, в котором SQL Server действительно оценивает их:
- Сначала вычисляется предложение FROM, чтобы предоставить исходные строки для остальной части инструкции. Создается виртуальная таблица, и затем передается на следующий шаг.
- Далее необходимо вычислить предложение WHERE, чтобы отфильтровать строки из исходной таблицы, соответствующие предикату. Отфильтрованная виртуальная таблица передается на следующий шаг.
- Здесь предложение GROUP BY упорядочивает строки в виртуальной таблице в соответствии с уникальными значениями, найденными в списке GROUP BY. Создается новая виртуальная таблица, содержащая список групп, и она передается на следующий шаг. С этого момента в потоке операций другие элементы могут ссылаться только на столбцы в списке GROUP BY или функциях агрегации.
- Далее вычисляется предложение HAVING путем фильтрации целых групп на основе его предиката. Виртуальная таблица, созданная на шаге 3, фильтруется и передается на следующий шаг.
- В конце выполняется предложение SELECT, определяя, какие столбцы будут отображаться в результатах запроса. Поскольку предложение SELECT вычисляется после выполнения других шагов, любые псевдонимы столбцов (в нашем примере Orders) не могут использоваться в предложении GROUP BY или HAVING.
- Предложение ORDER BY является последним выполняемым и оно сортирует строки согласно списку столбцов.
Чтобы применить это понимание к нашему примеру запроса, ниже приведен логический порядок выполнения инструкции SELECT, рассмотренной выше:
FROM Sales.SalesOrder
WHERE Status = 'Shipped'
GROUP BY OrderDate
HAVING COUNT(OrderID) > 1
SELECT OrderDate, COUNT(OrderID) AS Orders
ORDER BY OrderDate DESC;
Не все возможные предложения необходимы во всех используемых инструкциях SELECT. Единственным обязательным предложением является предложение SELECT, которое в некоторых случаях можно использовать самостоятельно. Обычно для указания запрашиваемой таблицы также добавляется предложение FROM. Кроме того, в языке Transact-SQL есть другие предложения, которые можно добавить.
Как вы уже видели, вы не пишете запросы T-SQL в том же порядке, в котором они логически обрабатываются. Порядок обработки определяет, какие данные доступны для предложений, так как предложение имеет доступ только к информации, доступной из уже обработанного предложения. По этой причине при написании запросов важно понимать фактический логический порядок обработки.
Выбор всех столбцов
Предложение SELECT часто называется списком SELECT, так как в нем содержится список значений, возвращаемых в результатах запроса.
Простейшая форма предложения SELECT: использовать символ звездочки (*), чтобы вернуть все столбцы. При использовании в запросах T-SQL он называется звездочка. Хотя SELECT * подходит для быстрой проверки, не следует использовать его в рабочей среде по нижеуказанным причинам.
- Изменения в таблице, которые добавляют или переупорядочивают столбцы, будут отражены в результатах запроса, что может привести к непредвиденным выходным данным для приложений или отчетов, использующих этот запрос.
- Возврат ненужных данных может замедлить выполнение запросов и вызвать проблемы с производительностью, если исходная таблица содержит большое количество строк.
Например, в следующем примере извлекаются все столбцы из (гипотетической) таблицы Production.Product.
SELECT * FROM Production.Product;
Результатом этого запроса является набор строк, содержащий все столбцы для всех строк таблицы, которые могут выглядеть примерно так:
ProductID
Имя.
ProductNum
Color
StandardCost
ПрейскурантнаяЦена
Размер
Вес
ProductCatID
680
HL Road Frame - Black, 58
FR-R92B-58
Черный
1059.31
1431.5
58
1016.04
18
706
HL Road Frame - Red, 58
FR-R92R-58
Красный
1059.31
1431.5
58
1016.04
18
707
Шлем Sport-100, красный
HL-U509-R
Красный
13.0863
34.99
35
708
Шлем Sport-100, черный
HL-U509
Черный
13.0863
34.99
35
...
...
...
...
...
...
...
...
...
Выбор конкретных столбцов
Явный список столбцов позволяет контролировать, какие именно столбцы и в каком порядке возвращаются. Каждый столбец в результате будет иметь имя столбца в качестве заголовка.
Например, рассмотрим следующий запрос; при этом используется гипотетическая таблица Production.Product.
SELECT ProductID, Name, ListPrice, StandardCost
FROM Production.Product;
На этот раз результаты содержат только указанные столбцы:
ProductID
Имя.
ПрейскурантнаяЦена
StandardCost
680
HL Road Frame - Black, 58
1431.5
1059.31
706
HL Road Frame - Red, 58
1431.5
1059.31
707
Шлем Sport-100, красный
34.99
13.0863
708
Шлем Sport-100, черный
34.99
13.0863
...
...
...
...
Выбор выражений
Помимо извлечения столбцов, хранящихся в указанной таблице, предложение SELECT может выполнять вычисления и манипуляции, которые используют операторы для объединения столбцов и значений или нескольких столбцов. Результатом вычисления или манипуляции должен быть однозначный (скалярный) результат, который в результате будет отображаться в виде отдельного столбца.
Например, следующий запрос содержит два выражения:
SELECT ProductID,
Name + '(' + ProductNumber + ')',
ListPrice - StandardCost
FROM Production.Product;
Результаты этого запроса могут выглядеть примерно так:
ProductID
680
HL Road Frame - Black, 58(FR-R92B-58)
372.19
706
HL Road Frame - Red, 58(FR-R92R-58)
372.19
707
Sport-100 Helmet, Red(HL-U509-R)
21.9037
708
Sport-100 Helmet, Black(HL-U509)
21.9037
...
...
...
Здесь следовало бы отметить несколько интересных особенностей.
- Столбцы, возвращаемые двумя выражениями, не имеют имен столбцов. В зависимости от инструмента, используемого для отправки запроса, имя отсутствующего столбца может быть указано пустым заголовком столбца, литералом "Без имени столбца" или именем по умолчанию, например column1. Далее в этом разделе мы покажем, как указать псевдоним для имени столбца в запросе.
- Первое выражение использует оператор + для (посимвольного) сцепления значений, а второе выражение использует оператор - для вычитания одного числового значения из другого. При использовании с числовыми значениями оператор + выполняет сложение. Очевидно, что важно понимать типы данных столбцов, добавляемых в выражения. Типы данных мы рассмотрим в следующем разделе.
Указание псевдонимов столбцов
Псевдоним можно указывать для каждого столбца, возвращаемого запросом SELECT, либо в качестве альтернативного имени исходного столбца, либо присвоив имя выходному выражению.
Например, вот тот же запрос, что и раньше, но с псевдонимами, указанными для каждого столбца:
SELECT ProductID AS ID,
Name + '(' + ProductNumber + ')' AS ProductName,
ListPrice - StandardCost AS Markup
FROM Production.Product;
Результаты этого запроса содержат указанные имена столбцов:
ID
НаименованиеПродукта
Разметка
680
HL Road Frame - Black, 58(FR-R92B-58)
372.19
706
HL Road Frame - Red, 58(FR-R92R-58)
372.19
707
Sport-100 Helmet, Red(HL-U509-R)
21.9037
708
Sport-100 Helmet, Black(HL-U509)
21.9037
...
...
...
Примечание.
Ключевое слово AS является необязательным при указании псевдонима, но для ясности рекомендуется включать его.
Форматирование запросов
Из примеров этого раздела можно увидеть, что в форматировании кода запроса есть определенная гибкость. Например, каждое предложение (или весь запрос) можно написать одной строкой или разбить на несколько строк. В большинстве систем баз данных код не учитывает регистр, а некоторые элементы языка T-SQL являются необязательными (включая ключевое слово AS, как упоминалось ранее, и даже точку с запятой в конце инструкции).
Придерживайтесь следующих рекомендаций, чтобы сделать код T-SQL легко читаемым (и, следовательно, легко понимаемым и легко отлаживаемым!):
- Записывайте прописью ключевые слова T-SQL, например SELECT, FROM, AS и т. д. Ключевые слова прописью — это часто используемое соглашение, которое упрощает поиск предложений в сложной инструкции.
- Начинайте каждое основное предложение инструкции с новой строки.
- Если список SELECT содержит больше нескольких столбцов, выражений или псевдонимов, рекомендуем перечислять каждый столбец в отдельной строке.
- Используйте отступы для строк, содержащих вложенные предложения или столбцы, чтобы показать, какой код относится к какому основному предложению.