SQL также великолепен во многих отношениях. Мы можем выписать самые сложные истины и факты, и база данных сообщит нам ответ в кратчайшие сроки.
Но язык SQL, пожалуй, самый красивый язык программирования. У него так много предостережений, что такие люди, как я, становятся смехотворно богатыми, продавая консалтинговые услуги, просто чтобы объяснить их семантику . Одним из лучших примеров того, как искажен язык SQL, является статья Алекса Боленка о SQL NULL на Tech.Pro .
В настоящее время одной из самых больших критик SQL является его многословие. Большинство диалектов SQL практически не имеют конструкций, позволяющих избежать повторения. Это распространенный случай использования в SQL для фильтрации, группировки, выбора и упорядочения по одному и тому же выражению. Пример:
|
1
2
3
4
5
|
SELECT first_name || ' ' || last_nameFROM customersWHERE first_name || ' ' || last_name LIKE 'L% E%'GROUP BY first_name || ' ' || last_nameORDER BY first_name || ' ' || last_name |
Вы можете написать другой запрос для того же, конечно. Но даже если вы этого не сделали, вас беспокоит, что вряд ли есть какой-либо способ повторно использовать first_name || ' ' || last_name first_name || ' ' || last_name конкатенационное выражение first_name || ' ' || last_name ?
Ну, вы можете, по крайней мере, повторно использовать его в предложении ORDER BY :
|
1
2
3
4
5
|
SELECT first_name || ' ' || last_name AS nameFROM customersWHERE first_name || ' ' || last_name LIKE 'L% E%'GROUP BY first_name || ' ' || last_nameORDER BY name |
А в MySQL вы также можете использовать его в предложении GROUP BY , хотя мы считаем, что это плохая идея :
|
1
2
3
4
5
|
SELECT first_name || ' ' || last_name AS nameFROM customersWHERE first_name || ' ' || last_name LIKE 'L% E%'GROUP BY nameORDER BY name |
Стандартные решения SQL для повторного использования столбцов
Конечно, вы можете создать производную таблицу:
|
1
2
3
4
5
6
7
8
|
SELECT nameFROM ( SELECT first_name || ' ' || last_name FROM customers) c(name)WHERE name LIKE 'L% E%'GROUP BY nameORDER BY name |
… Или общее табличное выражение, которое в основном является производной таблицей многократного использования, или локальное представление:
|
1
2
3
4
5
6
7
8
9
|
WITH c(name) AS ( SELECT first_name || ' ' || last_name FROM customers)SELECT nameFROM cWHERE name LIKE 'L% E%'GROUP BY nameORDER BY name |
Но почему мне даже нужно создать таблицу для повторного использования / переименования простого выражения столбца? Почему я не могу просто использовать что-то вроде выражения общего столбца ? Как это?
|
1
2
3
4
5
6
7
8
|
-- Common column expression that can be appended-- to any table expression.SELECT nameFROM customersWITH name AS first_name || ' ' || last_nameWHERE name LIKE 'L% E%'GROUP BY nameORDER BY name |
Обратите внимание, что выражение общего столбца будет ограничено источником таблицы. Другими словами, это имеет смысл только в контексте предложения FROM и таблиц, указанных в предложении FROM . В каком-то смысле следующие два выражения будут в точности эквивалентны:
|
01
02
03
04
05
06
07
08
09
10
|
-- Proposed syntaxFROM customersWITH name AS first_name || ' ' || last_name-- Existing syntaxFROM ( SELECT customers.*, first_name || ' ' || last_name AS name FROM customers) AS customers |
Предложенный синтаксис может также применяться к объединенным таблицам:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
-- Proposed syntaxFROM customers AS cWITH name AS c.first_name || ' ' || c.last_nameJOIN addresses AS aWITH address AS a.street || '\n' || a.city ON c.address_id = a.address_idWITH full_address AS c.name || '\n' || a.address-- Or alternatively, if you don't need to tightly -- scope these common column expressions to their-- corresponding tables:FROM customers AS cJOIN addresses AS a ON c.address_id = a.address_idWITH name AS c.first_name || ' ' || c.last_name, address AS a.street || '\n' || a.city, full_address AS name || '\n' || address |
Таким образом, в простом английском языке, новое предложение WITH может быть добавлено к любому типу табличного выражения. С круглыми скобками и комментариями первый из приведенных выше примеров будет выглядеть так:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
FROM ( customers AS c -- The "name" column is appended to "c" WITH name AS c.first_name || ' ' || c.last_name)JOIN ( addresses AS a -- The "address" column is appended to "a" WITH address AS a.street || '\n' || a.city) ON c.address_id = a.address_id-- The "full_address" column is appended to the-- above joined table expressionWITH full_address AS c.name || '\n' || a.address |
Приведенный выше синтаксис снова будет в точности эквивалентен этому:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
FROM ( SELECT c.*, a.*, c.name || '\n' || a.address AS full_address FROM ( SELECT c.*, c.first_name || ' ' || c.last_name FROM customers AS c ) c JOIN ( SELECT a.*, a.street || '\n' || a.city FROM addresses AS a ) a ON c.address_id = a.address_id) |
Самая недостающая языковая особенность SQL
Начиная с SQL: 1999 , у нас, к счастью, есть общие табличные выражения — предложение WITH , которое может быть добавлено перед любым SELECT (и другими операторами DML в некоторых диалектах). Используя общие табличные выражения, мы можем избежать повторения часто используемых производных таблиц.
Но такое не возможно для колонн. Таким образом, особенность SQL, которая наиболее необходима, — это обычные выражения столбцов .