Сайт FSA
07.02.2023

Первые шаги в SQL: SELECT

Эта заметка предназначена только для тех, кто первый раз знакомится с языком SQL. В ней нет ничего интересного для тех, кто этот язык запросов использует. Просто однажды возникла необходимость объяснить другому человеку как это работает. Если вы ни разу не писали свои запросы, но хотите научиться базовым вещам, тогда эта заметка для вас.

Далее в тексте словосочетание «база данных» я заменяю на БД.

SELECT

Запросы SELECT позволяют получить данные с сервера БД. Самый просто запрос состоит из списка данных, которые вы желаете получить из одной таблицы и имени этой таблицы:

SELECT * FROM users

Если необходимо получить строки из БД полностью, то просто указываем *. В данном случае мы попросили вернуть все строки из таблицы users, чтобы в каждой строке были все поля из этой таблицы.

Например в PHP: при использовании PDO каждый оператор fetch() или fetchObject() вернёт одну строку из результирующей таблицы, а fetchAll() вернёт массив из всех строк результата.

С помощью конструкции WHERE можно ограничить число строк, которые будут выданы сервером БД:

SELECT * FROM users WHERE id=1

В данном случае будет возвращена только одна или несколько строк, которые в поле таблицы id имеют значение 1. Часто поле id является уникальным. Поэтому данный запрос может вернуть одну строку или пустой результат, если строки с таким id не существует.

В таблицах БД может быть значительное число полей. Можно ограничить выдачу только теми полями, что нас интересуют:

SELECT id, name FROM users

Данный запрос вернёт данные из той же таблицы users, но каждая строка результата будет содержать только значение двух полей из этой таблицы: id и name. Если ваш код запросит большое число строк в которых есть большое количество данных в других полях, то запрос со * вернёт довольно большой объём данных, который нужно будет обработать. Указание конкретных полей сокращает количество передаваемых данных между сервером БД и сервером, где установлен PHP. Даже если это происходит внутри одного сервера, это может значительно снизить нагрузку на сервер.

Имена полей, которые указываются в запросах могут содержать не только имена конкретных столбцов таблицы, но и также имя таблицы. При этом используется формат имя_таблицы.имя_поля. Когда запрос производится только с использованием только одной таблицы, это делать бессмысленно, но можно, например:

SELECT users.id, users.name FROM users

Запрос полностью идентичен предыдущему. Хорошо, что наша таблица называется так коротко. Часто таблицы называют довольно сложно, чтобы было понятно для чего они предназначены, например, users_access_log. В таком случае нам придётся использовать это длинное наименование для указания, что нас интересует именно поле из этой конкретной таблицей. Чтобы этого не делать, можно использовать короткие алиасы для имён таблиц:

SELECT u.* FROM users u;

выбираем все поля из таблицы users, или

SELECT u.id, u.name FROM users u

выбираем поля id и name из таблицы users.

В обоих случаях мы присвоили таблице users алиас u и использовали его при указании имён полей. Можно указывать как конкретные имена полей, так и все с использованием символа *.

После того, как вы освоили алиасы, можно попробовать объединить данные из двух таблиц. Самое часто встречающееся объединение, это когда у вас есть какая-то таблица с данными и вам необходимо дополнить её данными из другой таблицы. Возьмём для примера две таблицы: users и time_tracker. Первая таблицы содержит информацию о пользователях, например, имена, адреса электронной почты и другое. Вторая таблица содержит информацию о времени, которое пользователи выполняли какую-то задачу. Структура второй таблицы не важна, главное, что в ней есть поле user_id, которое ссылается на id в таблице users.

Чтобы объединить таблицы используем LEFT JOIN. Есть и другие способы объединять таблицы, но этот самый распространённый.

SELECT * FROM time_tracker t LEFT JOIN users u ON u.id=t.user_id

В этом случае мы получим содержимое таблицы time_tracker, которое будет дополнено содержимым таблицы users. В каждой строке результата будет содержаться как данные из time_tracker, так и все поля для пользователя из таблицы users. Использование символа * не всегда самое лучшее решение. Можно использовать вариант t.*, u.*, который аналогичен представленному. Но лучше всего использовать конкретные имена интересующих полей. Если поле с таким именем есть в обоих таблицах, то можно изменить имя поля для результата, например, t.name, u.name AS user_name, в этом случае имя поля из таблицы time_tracker останется name без изменений, а поле из таблицы users будет переименовано в user_name.

Если изменить порядок связывания таблиц, то для каждой найденной в users строки в результате запроса будет создано такое количество строк, сколько строк соответствует этому пользователю в таблице time_tracker:

SELECT * FROM users u LEFT JOIN time_tracker t ON u.id=t.user_id

Аналогичный этому запрос можно сделать из предыдущего заменив LEFT на RIGHT:

SELECT * FROM time_tracker t RIGHT JOIN users u ON u.id=t.user_id

Но, обычно, такие запросы не используют. Они, хоть и корректные, но усложняет чтение кода. В случае с RIGHT JOIN производится объединение таблицы справа с таблицей слева. Хорошо, если это две таблицы. А если объединение используется несколько раз в запросе? Тогда RIGHT JOIN просто усложняет понимание человеком.

Ко всем запросам может быть добавлено условие WHERE, где можно указать то, что вы хотите получить из выборки.

Далее можно указать порядок выборки с помощью ORDER, где необходимо указать поля, по которым необходимо сортировать результат. Если используется сортировка, то стоит проверить, что для тех полей, что использует сортировку, создан индекс. В ином случае сервер баз данных будет дольше сортировать данных перед выборкой, т.к. не будет использовать индекс.


Обратите внимание, что заметки могут обновляться со временем. Это может быть как исправление найденных ошибок, так и доработка содержания с целью более полного раскрытия темы. Информация об изменениях доступна в репозитории на github. Там же вы можете оставить в Issue ваши замечания по данной заметке.


Если данная заметка оказалась вам полезной, можете поблагодарить автора финансово.