SQL также великолепен во многих отношениях. Мы можем выписать самые сложные истины и факты, и база данных сообщит нам ответ в кратчайшие сроки.
Но язык SQL, пожалуй, самый красивый язык программирования. У него так много предостережений, что такие люди, как я, становятся смехотворно богатыми, продавая консалтинговые услуги, просто чтобы объяснить их семантику . Одним из лучших примеров того, как искажен язык SQL, является статья Алекса Боленка о SQL NULL на Tech.Pro .
В настоящее время одной из самых больших критик SQL является его многословие. Большинство диалектов SQL практически не имеют конструкций, позволяющих избежать повторения. Это распространенный случай использования в SQL для фильтрации, группировки, выбора и упорядочения по одному и тому же выражению. Пример:
1
2
3
4
5
|
SELECT first_name || ' ' || last_name FROM customers WHERE first_name || ' ' || last_name LIKE 'L% E%' GROUP BY first_name || ' ' || last_name ORDER 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 name FROM customers WHERE first_name || ' ' || last_name LIKE 'L% E%' GROUP BY first_name || ' ' || last_name ORDER BY name |
А в MySQL вы также можете использовать его в предложении GROUP BY
, хотя мы считаем, что это плохая идея :
1
2
3
4
5
|
SELECT first_name || ' ' || last_name AS name FROM customers WHERE first_name || ' ' || last_name LIKE 'L% E%' GROUP BY name ORDER BY name |
Стандартные решения SQL для повторного использования столбцов
Конечно, вы можете создать производную таблицу:
1
2
3
4
5
6
7
8
|
SELECT name FROM ( SELECT first_name || ' ' || last_name FROM customers ) c( name ) WHERE name LIKE 'L% E%' GROUP BY name ORDER BY name |
… Или общее табличное выражение, которое в основном является производной таблицей многократного использования, или локальное представление:
1
2
3
4
5
6
7
8
9
|
WITH c( name ) AS ( SELECT first_name || ' ' || last_name FROM customers ) SELECT name FROM c WHERE name LIKE 'L% E%' GROUP BY name ORDER BY name |
Но почему мне даже нужно создать таблицу для повторного использования / переименования простого выражения столбца? Почему я не могу просто использовать что-то вроде выражения общего столбца ? Как это?
1
2
3
4
5
6
7
8
|
-- Common column expression that can be appended -- to any table expression. SELECT name FROM customers WITH name AS first_name || ' ' || last_name WHERE name LIKE 'L% E%' GROUP BY name ORDER BY name |
Обратите внимание, что выражение общего столбца будет ограничено источником таблицы. Другими словами, это имеет смысл только в контексте предложения FROM
и таблиц, указанных в предложении FROM
. В каком-то смысле следующие два выражения будут в точности эквивалентны:
01
02
03
04
05
06
07
08
09
10
|
-- Proposed syntax FROM customers WITH name AS first_name || ' ' || last_name -- Existing syntax FROM ( 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 syntax FROM customers AS c WITH name AS c.first_name || ' ' || c.last_name JOIN addresses AS a WITH address AS a.street || '\n' || a.city ON c.address_id = a.address_id WITH 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 c JOIN addresses AS a ON c.address_id = a.address_id WITH 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 expression WITH 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, которая наиболее необходима, — это обычные выражения столбцов .