Список колонок и звёздочка
Запрос начинается со списка колонок. Пишут их через запятую сразу после слова SELECT, а после FROM — имя таблицы, откуда их брать.
SELECT title, price FROM products
Пятнадцать строк, две колонки. Первые из них выглядят так:
| title | price |
|---|---|
| Ноутбук Pro 14 | 89990 |
| Смартфон X | 54990 |
| Наушники Air | 12990 |
| Клавиатура Mech | 7490 |
Главное, что стоит заметить: строк осталось пятнадцать — столько же, сколько в таблице. Список после SELECT вырезает из таблицы вертикальную полосу и не трогает строки вовсе. Отсекать строки будет WHERE, и это следующий урок.
Порядок колонок в результате — тот, в каком вы их перечислили, а не тот, в каком они лежат в таблице. SELECT price, title даст сначала цену, потом название. Для глаз это мелочь, а для программы, которая читает результат по номеру колонки, — нет.
Вместо списка можно написать звёздочку: SELECT * FROM products вернёт все пять колонок в том порядке, в каком они объявлены в таблице.
Ещё две мелочи, которые пригодятся сразу.
Одну и ту же колонку можно перечислить дважды — база не возражает: SELECT title, title FROM products вернёт две одинаковые колонки. Само по себе это не нужно, но перестаёт удивлять, когда такое встречается в чужом запросе после правки.
А имя колонки, которой в таблице нет, — это ошибка, и база скажет о ней сразу, до всякого выполнения. Ошибиться в имени легко: name есть у покупателей и сотрудников, а у товаров колонка называется title. Такие ошибки — самые дешёвые: они находятся в первую секунду.
Колонку можно называть вместе с таблицей, через точку: products.title. Пока таблица одна, это лишние буквы, и так почти не пишут. Но как только в запросе появится вторая таблица, выяснится, что колонка id есть у обеих, — и без уточнения база не поймёт, о какой из них речь. Привыкать заранее не нужно; достаточно знать, что запись законна и что она означает.
И вопрос, который стоит решить сразу: сколько колонок брать. Ответ короткий — ровно те, что нужны. Каждая лишняя колонка это данные, которые база прочитала, передала по сети и показала, а читатель пролистал. На пятнадцати товарах разница неощутима, на миллионе строк лишняя текстовая колонка превращает секунду в минуту.
Псевдонимы: имя колонки в ответе
Колонка в результате получает имя. По умолчанию это имя из таблицы — title, price. Заменить его можно псевдонимом: слово AS и новое имя.
SELECT title AS Товар, price AS Цена FROM products
Данные при этом те же до последнего знака: меняется только подпись столбца в ответе.
Зачем это нужно. Во-первых, результат запроса часто уходит человеку — в отчёт, в таблицу, в письмо, — и заголовок «price» там читается хуже, чем «Цена». Во-вторых, у вычисленной колонки своего имени нет вовсе, и без псевдонима она получит от базы что-нибудь вроде price * 0.9 — заголовок, который невозможно ни прочитать, ни использовать.
Имя из одного слова пишут как есть. Имя с пробелом, запятой или знаком берут в двойные кавычки:
SELECT title AS "Название товара",
price AS "Цена, ₽"
FROM products
Само слово AS необязательно: price Цена работает так же. Писать его всё же стоит — без него пропущенная запятая превращается в псевдоним и молча съедает колонку:
-- забыта запятая: две колонки вместо трёх SELECT title, price stock FROM products
Здесь база решит, что stock — это псевдоним для price, и вернёт колонку «stock», в которой лежат цены. Ни ошибки, ни предупреждения; ошибку находят потом, в отчёте, где остатки подозрительно похожи на цены.
И последнее: псевдоним нельзя использовать в том же SELECT, где он объявлен, — так же, как его нельзя использовать в WHERE. Причина та же: имена появляются все разом, в конце вычисления списка. Нужна колонка, посчитанная из другой вычисленной, — выражение повторяют целиком или разбивают запрос на два, и этому посвящён урок про подзапросы.
Псевдоним бывает не только у колонки, но и у таблицы — короткое имя после FROM:
SELECT p.title, p.price FROM products AS p
Здесь это пока лишняя работа: таблица одна, и уточнять нечего. Смысл появится в уроке про соединения, где таблиц станет три, а у каждой найдётся колонка id. Тогда короткое имя из одной-двух букв окажется единственным способом написать запрос так, чтобы его можно было прочитать.
Правило то же, что у колонок: слово AS необязательно (FROM products p работает), а имя из одного слова пишут без кавычек. И то же предостережение: объявив псевдоним таблицы, дальше пользуются им. Смешивать в одном запросе p.title и products.title база разрешит не всегда, а прочитать такое не сможет никто.
Выражения в списке колонок
В списке колонок может стоять не только имя, но и выражение. База посчитает его для каждой строки и вернёт результат новой колонкой.
SELECT title,
price,
price * 0.9 AS "Цена со скидкой"
FROM products
У ноутбука за 89 990 в третьей колонке окажется 80 991. Строк по-прежнему пятнадцать: выражение считается для каждой строки отдельно и ничего не складывает между строками. Складывать умеют агрегаты, и до них ещё два урока.
| что можно | пример | что получится |
|---|---|---|
| Арифметика | price * 2 | число |
| Скобки и порядок | (price + 100) * 2 | число |
| Деление | price / 12 | число, но осторожно |
| Склейка текста | city || ', ' || name | текст |
| Число прямо в запросе | 0.9 | одно и то же во всех строках |
Про деление стоит сказать отдельно, потому что на нём спотыкаются все. Во многих базах деление двух целых чисел даёт целое: 7 / 2 — это 3, а не 3,5. Дробная часть не округляется, а отбрасывается. Лечится это умножением на 1.0: 7 * 1.0 / 2 уже даст 3,5.
Склейка текста обозначается двумя вертикальными чертами:
SELECT name || ' (' || city || ')' AS "Покупатель"
FROM customers
Получится «Анна Смирнова (Москва)». Знаки препинания и пробелы пишутся отдельными кусочками текста в одинарных кавычках — база сама ничего не подставляет.
И ещё одна вещь, которая поначалу выглядит бессмыслицей: в списке колонок можно написать просто число или просто текст. SELECT title, 1 AS Проверено FROM products вернёт колонку из пятнадцати единиц. Пригождается это чаще, чем кажется: так помечают строки, пришедшие из разных источников, когда результаты двух запросов складывают вместе.
Порядок действий в выражении обычный, школьный: сначала умножение и деление, потом сложение и вычитание, скобки сильнее всего. price + 100 * 2 — это цена плюс двести, а не цена плюс сто, умноженная на два. Ошибка выглядит безобидно и не даёт о себе знать ничем, кроме неверного числа в отчёте, поэтому скобки ставят даже там, где можно не ставить.
И ещё одно, что пригодится в следующих уроках: выражения живут не только в списке колонок. Ту же арифметику можно написать в WHERE («где цена со скидкой больше десяти тысяч») и в ORDER BY («по сумме строки заказа»). Правила везде одни и те же — и целочисленное деление, и пустота в склейке ведут себя одинаково, в какой бы части запроса выражение ни стояло.
DISTINCT: только разные
Последнее, что умеет SELECT сам по себе, — убирать повторы. Слово DISTINCT ставится сразу после него и означает «оставить только разные строки».
SELECT DISTINCT category FROM products
В таблице пятнадцать товаров, но категорий у них всего пять: электроника, аксессуары, бытовая техника, книги, мебель. Без DISTINCT запрос вернул бы пятнадцать строк, из которых «Электроника» встретилась бы пять раз.
Это самый частый способ узнать, что вообще лежит в колонке. Незнакомая таблица, колонка status — что в ней бывает? Один запрос, и видно: done, cancelled, shipped, new, paid. Пять значений, и теперь можно писать условия, не гадая.
Второе, что стоит знать: пустота считается значением. Если в колонке есть незаполненные клетки, DISTINCT вернёт одну строку и для них тоже — и две пустые клетки посчитает одинаковыми, хотя обычные сравнения ведут себя с пустотой иначе. Это одно из немногих мест, где пустота ведёт себя предсказуемо.
И третье, менее очевидное: DISTINCT — не бесплатная операция. Чтобы убрать повторы, базе надо сравнить строки между собой, то есть отсортировать их или построить таблицу виденного. На пятнадцати строках это ничто, на десяти миллионах — заметная работа.
Отсюда привычка, которая отличает рабочий запрос от учебного: DISTINCT не ставят на всякий случай. Когда он появляется в запросе не потому, что нужны разные значения, а потому, что «строк как-то много и они задвоились», — это признак, что задвоил их не SELECT, а соединение таблиц. Лечить надо соединение, а DISTINCT только прячет симптом: уроку про размножение строк посвящён отдельный разговор.
Раз есть DISTINCT, должно быть и обратное — и оно есть: ALL. SELECT ALL city FROM customers означает «со всеми повторами», то есть ровно то, что происходит без единого слова. Пишут его редко, почти только в чужом коде и в учебниках, — но встретив, теперь знаете, что он ничего не меняет.
Второй вопрос возникает чуть позже и стоит того, чтобы ответить на него заранее: чем DISTINCT отличается от GROUP BY. Списком разных значений — ничем: SELECT DISTINCT city FROM customers и SELECT city FROM customers GROUP BY city дают одно и то же. Разница в том, что умеет второй: сгруппировав строки, он может ещё и посчитать по каждой группе — сколько покупателей в городе, какая там средняя цена.