CONCAT в SQL — это способ склеить несколько значений в одну строку.
Например, у нас есть имя и фамилия в разных колонках:
- имя: Анна
- фамилия: Петрова
А на сайте нужно показать красиво:
Анна Петрова
Вот для этого и нужна конкатенация: она берёт кусочки текста и собирает из них одну готовую строку.
На первый взгляд всё просто: «ну что там, склеить две строки». Но в SQL есть важная ловушка: разные способы склейки по-разному ведут себя с NULL. А NULL в базе встречается часто: у пользователя может не быть отчества, у адреса — квартиры, у товара — описания.
Из-за этого легко получить неприятный баг: хотели вывести полное имя, а у части пользователей вместо имени внезапно получилось NULL.
Разберём спокойно и по-человечески:
- оператор
||;
- функцию
CONCAT;
- функцию
CONCAT_WS;
- чем они отличаются;
- почему для имён и адресов чаще всего лучше брать
CONCAT_WS.
Зачем вообще склеивать строки в SQL
Конкатенация нужна, когда данные хранятся в таблице по частям, а показать их нужно одной красивой строкой.
Типичные примеры:
- собрать полное имя из имени, отчества и фамилии;
- собрать адрес из улицы, квартиры, города и страны;
- собрать ссылку из домена и пути;
- сформировать подпись, сообщение, slug или строку для отчёта;
- вывести текст вроде
Order #42.
Допустим, есть таблица пользователей:
| id |
first_name |
last_name |
| 1 |
Anna |
Petrova |
| 2 |
Boris |
Sidorov |
Можно получить полное имя прямо в запросе:
SELECT
first_name,
last_name,
CONCAT(first_name, ' ', last_name) AS full_name
FROM users;
Результат:
| first_name |
last_name |
full_name |
| Anna |
Petrova |
Anna Petrova |
| Boris |
Sidorov |
Boris Sidorov |
То есть SQL не просто достаёт сырые поля, а сразу готовит данные в удобном для отображения виде.
Способ 1. Оператор ||
Оператор || — это стандартный способ конкатенации в SQL.
Пример:
SELECT 'Hello, ' || 'World' AS message;
Результат:
Можно склеивать не только две строки, а сколько угодно частей:
SELECT 'User: ' || first_name || ' ' || last_name AS user_label
FROM users;
Получится что-то вроде:
| user_label |
| User: Anna Petrova |
| User: Boris Sidorov |
Оператор || работает, например, в PostgreSQL, SQLite, Oracle и DB2.
Но есть важный момент: в MySQL по умолчанию || не склеивает строки. Там он воспринимается как логическое OR. Поэтому если вы пишете запросы под MySQL, для склейки строк обычно используют CONCAT.
Главная ловушка оператора || — NULL
Вот тут начинается самое важное.
Посмотрим на простой пример:
SELECT 'Hello, ' || NULL AS message;
Результат будет:
Почему так?
Потому что NULL в SQL означает не «пустая строка», а неизвестное значение.
SQL рассуждает примерно так:
Я знаю первую часть строки: Hello, .
Но вторая часть неизвестна.
Значит, весь результат тоже неизвестен.
То же самое произойдёт, если NULL окажется где-то в середине:
SELECT 'Hello, ' || NULL || '!' AS message;
Результат:
Один NULL ломает всю строку.
На практике это часто всплывает с отчеством, квартирой, дополнительной строкой адреса, комментарием или любым необязательным полем.
Как защититься через COALESCE
Если вы всё-таки используете ||, можно заранее заменить NULL на запасное значение через COALESCE.
Например:
SELECT
'Hello, ' || COALESCE(name, 'Guest') AS message
FROM users;
Если name есть, будет имя. Если name равен NULL, подставится Guest.
Для полного имени можно написать так:
SELECT
COALESCE(first_name, '') || ' ' || COALESCE(last_name, '') AS full_name
FROM users;
Но у этого подхода есть минус: легко получить лишние пробелы.
Например, если фамилии нет, результат может быть таким:
Визуально после Anna может остаться лишний пробел. С именами это ещё терпимо, а вот с адресами начинаются двойные пробелы, лишние запятые и некрасивые строки.
Способ 2. CONCAT
CONCAT — это функция для склейки строк.
Пример:
SELECT CONCAT('Hello, ', 'World') AS message;
Результат:
Можно передать больше двух аргументов:
SELECT CONCAT('a', 'b', 'c', 'd') AS result;
Результат:
Для полного имени:
SELECT
CONCAT(first_name, ' ', last_name) AS full_name
FROM users;
CONCAT есть в PostgreSQL, MySQL и SQL Server. В SQLite чаще используют оператор ||, хотя в некоторых версиях и сборках может быть доступна функция concat.
Главное отличие CONCAT от || — поведение с NULL.
Как CONCAT работает с NULL
Посмотрим:
SELECT CONCAT('Hello, ', NULL, '!') AS message;
Результат:
CONCAT обычно воспринимает NULL как пустую строку. То есть он не ломает весь результат, а просто пропускает неизвестное значение как пустое место.
Это удобно.
Но не идеально.
Например, соберём имя, отчество и фамилию:
SELECT
CONCAT(first_name, ' ', middle_name, ' ', last_name) AS full_name
FROM users;
Если middle_name равен NULL, результат может получиться таким:
Обратите внимание: между Boris и Sidorov два пробела.
Почему?
Потому что CONCAT пропустил само значение middle_name, но пробелы вокруг него остались:
first_name + ' ' + NULL + ' ' + last_name
NULL исчез, а два разделителя остались.
Именно поэтому для имён, адресов и похожих задач часто лучше подходит не просто CONCAT, а CONCAT_WS.
Способ 3. CONCAT_WS
CONCAT_WS расшифровывается как concat with separator — «склеить с разделителем».
Первый аргумент — это разделитель. Остальные аргументы — значения, которые нужно склеить.
Пример:
SELECT CONCAT_WS(', ', 'Anna', 'Moscow', 'Russia') AS address;
Результат:
| address |
| Anna, Moscow, Russia |
Разделитель , автоматически вставляется между значениями.
Теперь самое приятное: CONCAT_WS пропускает NULL и не ставит лишние разделители.
SELECT CONCAT_WS(', ', 'Anna', NULL, 'Russia') AS address;
Результат:
Без двойных запятых. Без дырок. Без ручного CASE.
Это и есть главная сила CONCAT_WS.
CONCAT_WS для полного имени
Допустим, у пользователя может быть отчество, а может не быть.
Плохая новость: если склеивать через ||, можно получить NULL.
Средняя новость: если склеивать через CONCAT, можно получить лишние пробелы.
Хорошая новость: CONCAT_WS решает задачу аккуратно.
SELECT
CONCAT_WS(' ', first_name, middle_name, last_name) AS full_name
FROM users;
Если все три части есть:
| full_name |
| Anna Ivanovna Petrova |
Если отчества нет:
Никакого двойного пробела.
CONCAT_WS для адреса
С адресами ситуация ещё показательнее.
Адрес часто состоит из нескольких частей:
- улица;
- дом;
- квартира;
- город;
- страна.
Но квартира может быть не указана. Район может быть не указан. Индекс может быть не указан.
Вот хороший вариант:
SELECT
CONCAT_WS(', ', street, apartment, city, country) AS full_address
FROM addresses;
Если все поля заполнены:
| full_address |
| Main St, Apt 12, Boston, USA |
Если квартиры нет:
| full_address |
| Main St, Boston, USA |
CONCAT_WS не оставляет строку вида:
Main St, , Boston, USA
Именно поэтому его так любят для адресов, имён и человекочитаемых строк.
Сравним три способа на одной таблице
Пусть есть таблица users:
| id |
first_name |
middle_name |
last_name |
| 1 |
Anna |
Ivanovna |
Petrova |
| 2 |
Boris |
NULL |
Sidorov |
| 3 |
NULL |
NULL |
NULL |
Сравним ||, CONCAT и CONCAT_WS:
SELECT
id,
first_name || ' ' || middle_name || ' ' || last_name AS via_pipes,
CONCAT(first_name, ' ', middle_name, ' ', last_name) AS via_concat,
CONCAT_WS(' ', first_name, middle_name, last_name) AS via_concat_ws
FROM users;
Результат будет примерно таким:
| id |
via_pipes |
via_concat |
via_concat_ws |
| 1 |
Anna Ivanovna Petrova |
Anna Ivanovna Petrova |
Anna Ivanovna Petrova |
| 2 |
NULL |
Boris Sidorov |
Boris Sidorov |
| 3 |
NULL |
|
|
Что здесь произошло:
|| сломался на строке с Борисом, потому что middle_name равен NULL;
CONCAT не сломался, но оставил двойной пробел;
CONCAT_WS дал самый аккуратный результат.
Поэтому для полного имени почти всегда лучше использовать:
SELECT
CONCAT_WS(' ', first_name, middle_name, last_name) AS full_name
FROM users;
А для адреса:
SELECT
CONCAT_WS(', ', street, apartment, city, country) AS full_address
FROM addresses;
CONCAT и числа
Конкатенация умеет работать не только со строками. Числа и даты часто автоматически приводятся к тексту.
Например:
SELECT CONCAT('Order #', 42) AS label;
Результат:
Ещё пример:
SELECT CONCAT_WS('-', 2024, 12, 31) AS date_text;
Результат:
Это удобно, но есть нюанс: автоматическое преобразование не всегда даёт тот формат, который вы хотите.
Например, дата может отобразиться в одном формате в одной базе и в другом формате в другой. Число с дробной частью тоже может выглядеть не так, как нужно для интерфейса или отчёта.
Если формат важен, лучше явно управлять преобразованием.
В PostgreSQL можно так:
SELECT
'Price: ' || price::TEXT AS price_label
FROM products;
Для даты часто используют форматирование:
SELECT
'Date: ' || TO_CHAR(created_at, 'YYYY-MM-DD') AS created_label
FROM orders;
Так вы явно говорите базе: «покажи дату именно в таком виде».
Конкатенация в WHERE: почему нужно быть осторожным
Конкатенация сама по себе обычно дешёвая операция. В большинстве обычных запросов она не будет проблемой.
Но есть важный случай: не стоит бездумно склеивать поля в WHERE.
Например:
SELECT *
FROM users
WHERE first_name || ' ' || last_name = 'Anna Petrova';
Запрос выглядит понятно, но для базы это может быть неудобно.
Если у вас есть отдельные индексы по first_name и last_name, выражение со склейкой может помешать использовать их эффективно. Базе приходится сначала собрать строку, а потом сравнить её с нужным значением.
Чаще лучше написать условие по отдельным колонкам:
SELECT *
FROM users
WHERE first_name = 'Anna'
AND last_name = 'Petrova';
Так базе проще использовать индексы.
Если же полное имя реально часто нужно искать или сортировать как одну строку, можно завести отдельную колонку full_name, например вычисляемую, и индексировать уже её.
Конкатенация в ORDER BY
Похожая история с сортировкой.
Можно написать так:
SELECT
id,
CONCAT_WS(' ', first_name, last_name) AS full_name
FROM users
ORDER BY CONCAT_WS(' ', first_name, last_name);
Для небольших таблиц это нормально.
Но если таблица большая и такая сортировка используется часто, лучше подумать о готовом поле или функциональном индексе, если ваш диалект SQL это поддерживает.
Главная мысль простая: собрать красивую строку для вывода — нормально. Но если вы по этой строке постоянно ищете, фильтруете и сортируете, возможно, она заслуживает отдельного места в структуре данных.
Частые ошибки новичков
Ошибка 1. Использовать || и забыть про NULL
Пишут так:
SELECT
first_name || ' ' || middle_name || ' ' || last_name AS full_name
FROM users;
А потом удивляются, почему у пользователя без отчества полное имя стало NULL.
Если поле может быть пустым, используйте COALESCE, CONCAT или лучше CONCAT_WS.
Ошибка 2. Использовать || в MySQL
В PostgreSQL такой запрос склеит строки:
SELECT 'Hello, ' || 'World' AS message;
А в MySQL по умолчанию || — это логическое OR, а не конкатенация.
Для MySQL используйте:
SELECT CONCAT('Hello, ', 'World') AS message;
Если пишете код, который должен быть понятен в разных SQL-диалектах, CONCAT часто безопаснее, чем ||.
Ошибка 3. Получить лишние пробелы через CONCAT
Вот такой запрос не сломается на NULL:
SELECT
CONCAT(first_name, ' ', middle_name, ' ', last_name) AS full_name
FROM users;
Но если middle_name равен NULL, можно получить двойной пробел.
Для полного имени лучше так:
SELECT
CONCAT_WS(' ', first_name, middle_name, last_name) AS full_name
FROM users;
Ошибка 4. Получить лишние запятые в адресе
Новичок часто пишет:
SELECT
CONCAT(street, ', ', apartment, ', ', city, ', ', country) AS full_address
FROM addresses;
Если apartment равен NULL, результат может выглядеть некрасиво:
Main St, , Boston, USA
Лучше:
SELECT
CONCAT_WS(', ', street, apartment, city, country) AS full_address
FROM addresses;
Так NULL будет пропущен вместе с лишней запятой.
Ошибка 5. Думать, что конкатенация и сложение — одно и то же
В некоторых диалектах для строк может использоваться один оператор, в других — другой.
Например, в SQL Server оператор + может использоваться для строк:
SELECT 'Hello, ' + 'World' AS message;
Но с числами + — это уже сложение:
SELECT 42 + 7 AS result;
Результат будет 49, а не 427.
Поэтому для строк лучше использовать понятные строковые функции, например CONCAT, особенно если вы только учитесь и не хотите путаться в особенностях диалектов.
Ошибка 6. Делать CSV через простую склейку
Иногда кажется, что CSV можно собрать так:
SELECT
CONCAT_WS(', ', name, city, country) AS csv_line
FROM users;
Для простого отображения это нормально. Но для настоящего CSV-экспорта опасно.
Если внутри значения уже есть запятая, строка может сломаться для CSV-парсера.
Например:
| name |
city |
country |
| Anna, friend |
Moscow |
Russia |
Простая склейка даст:
Anna, friend, Moscow, Russia
Выглядит как четыре поля вместо трёх.
Для настоящего CSV нужны экранирование, кавычки и нормальный экспортный механизм, а не просто CONCAT_WS.
Как выбрать правильный способ
Простое правило:
| Задача |
Что использовать |
| Склеить строки в PostgreSQL или SQLite |
` |
| Склеить строки более универсально |
CONCAT |
| Склеить поля с разделителем |
CONCAT_WS |
| Собрать полное имя |
CONCAT_WS |
| Собрать адрес |
CONCAT_WS |
Защититься от NULL без лишних разделителей |
CONCAT_WS |
| Сделать строгий формат даты или числа |
явное форматирование |
Если сомневаетесь, запомните практическую формулу:
Для человекочитаемых строк с пробелами, запятыми и необязательными полями чаще всего нужен CONCAT_WS.
Главное
Конкатенация в SQL — это склейка нескольких значений в одну строку.
Есть три популярных способа:
|| — стандартный SQL-оператор, но один NULL превращает весь результат в NULL.
CONCAT — функция склейки, которая обычно воспринимает NULL как пустую строку.
CONCAT_WS — склейка с разделителем, которая пропускает NULL и не оставляет лишние пробелы или запятые.
Для простых строк подойдёт CONCAT.
Для имён, адресов, подписей и других строк, где часть полей может быть NULL, чаще всего лучший выбор — CONCAT_WS.
И ещё одно важное правило: склеивать строки для красивого вывода — нормально. Но если вы часто фильтруете или сортируете по склеенной строке, подумайте об отдельной колонке, вычисляемом поле или индексе. Так запросы будут не только красивыми, но и быстрыми.
CONCATв SQL — это способ склеить несколько значений в одну строку.Например, у нас есть имя и фамилия в разных колонках:
А на сайте нужно показать красиво:
Анна Петрова
Вот для этого и нужна конкатенация: она берёт кусочки текста и собирает из них одну готовую строку.
На первый взгляд всё просто: «ну что там, склеить две строки». Но в SQL есть важная ловушка: разные способы склейки по-разному ведут себя с
NULL. АNULLв базе встречается часто: у пользователя может не быть отчества, у адреса — квартиры, у товара — описания.Из-за этого легко получить неприятный баг: хотели вывести полное имя, а у части пользователей вместо имени внезапно получилось
NULL.Разберём спокойно и по-человечески:
||;CONCAT;CONCAT_WS;CONCAT_WS.Зачем вообще склеивать строки в SQL
Конкатенация нужна, когда данные хранятся в таблице по частям, а показать их нужно одной красивой строкой.
Типичные примеры:
Order #42.Допустим, есть таблица пользователей:
Можно получить полное имя прямо в запросе:
SELECT first_name, last_name, CONCAT(first_name, ' ', last_name) AS full_name FROM users;Результат:
То есть SQL не просто достаёт сырые поля, а сразу готовит данные в удобном для отображения виде.
Способ 1. Оператор ||
Оператор
||— это стандартный способ конкатенации в SQL.Пример:
SELECT 'Hello, ' || 'World' AS message;Результат:
Можно склеивать не только две строки, а сколько угодно частей:
SELECT 'User: ' || first_name || ' ' || last_name AS user_label FROM users;Получится что-то вроде:
Оператор
||работает, например, в PostgreSQL, SQLite, Oracle и DB2.Но есть важный момент: в MySQL по умолчанию
||не склеивает строки. Там он воспринимается как логическоеOR. Поэтому если вы пишете запросы под MySQL, для склейки строк обычно используютCONCAT.Главная ловушка оператора || — NULL
Вот тут начинается самое важное.
Посмотрим на простой пример:
SELECT 'Hello, ' || NULL AS message;Результат будет:
Почему так?
Потому что
NULLв SQL означает не «пустая строка», а неизвестное значение.SQL рассуждает примерно так:
То же самое произойдёт, если
NULLокажется где-то в середине:SELECT 'Hello, ' || NULL || '!' AS message;Результат:
Один
NULLломает всю строку.На практике это часто всплывает с отчеством, квартирой, дополнительной строкой адреса, комментарием или любым необязательным полем.
Как защититься через COALESCE
Если вы всё-таки используете
||, можно заранее заменитьNULLна запасное значение черезCOALESCE.Например:
SELECT 'Hello, ' || COALESCE(name, 'Guest') AS message FROM users;Если
nameесть, будет имя. ЕслиnameравенNULL, подставитсяGuest.Для полного имени можно написать так:
SELECT COALESCE(first_name, '') || ' ' || COALESCE(last_name, '') AS full_name FROM users;Но у этого подхода есть минус: легко получить лишние пробелы.
Например, если фамилии нет, результат может быть таким:
Визуально после
Annaможет остаться лишний пробел. С именами это ещё терпимо, а вот с адресами начинаются двойные пробелы, лишние запятые и некрасивые строки.Способ 2. CONCAT
CONCAT— это функция для склейки строк.Пример:
SELECT CONCAT('Hello, ', 'World') AS message;Результат:
Можно передать больше двух аргументов:
SELECT CONCAT('a', 'b', 'c', 'd') AS result;Результат:
Для полного имени:
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users;CONCATесть в PostgreSQL, MySQL и SQL Server. В SQLite чаще используют оператор||, хотя в некоторых версиях и сборках может быть доступна функцияconcat.Главное отличие
CONCATот||— поведение сNULL.Как CONCAT работает с NULL
Посмотрим:
SELECT CONCAT('Hello, ', NULL, '!') AS message;Результат:
CONCATобычно воспринимаетNULLкак пустую строку. То есть он не ломает весь результат, а просто пропускает неизвестное значение как пустое место.Это удобно.
Но не идеально.
Например, соберём имя, отчество и фамилию:
SELECT CONCAT(first_name, ' ', middle_name, ' ', last_name) AS full_name FROM users;Если
middle_nameравенNULL, результат может получиться таким:Обратите внимание: между
BorisиSidorovдва пробела.Почему?
Потому что
CONCATпропустил само значениеmiddle_name, но пробелы вокруг него остались:first_name + ' ' + NULL + ' ' + last_nameNULLисчез, а два разделителя остались.Именно поэтому для имён, адресов и похожих задач часто лучше подходит не просто
CONCAT, аCONCAT_WS.Способ 3. CONCAT_WS
CONCAT_WSрасшифровывается как concat with separator — «склеить с разделителем».Первый аргумент — это разделитель. Остальные аргументы — значения, которые нужно склеить.
Пример:
SELECT CONCAT_WS(', ', 'Anna', 'Moscow', 'Russia') AS address;Результат:
Разделитель
,автоматически вставляется между значениями.Теперь самое приятное:
CONCAT_WSпропускаетNULLи не ставит лишние разделители.SELECT CONCAT_WS(', ', 'Anna', NULL, 'Russia') AS address;Результат:
Без двойных запятых. Без дырок. Без ручного
CASE.Это и есть главная сила
CONCAT_WS.CONCAT_WS для полного имени
Допустим, у пользователя может быть отчество, а может не быть.
Плохая новость: если склеивать через
||, можно получитьNULL.Средняя новость: если склеивать через
CONCAT, можно получить лишние пробелы.Хорошая новость:
CONCAT_WSрешает задачу аккуратно.SELECT CONCAT_WS(' ', first_name, middle_name, last_name) AS full_name FROM users;Если все три части есть:
Если отчества нет:
Никакого двойного пробела.
CONCAT_WS для адреса
С адресами ситуация ещё показательнее.
Адрес часто состоит из нескольких частей:
Но квартира может быть не указана. Район может быть не указан. Индекс может быть не указан.
Вот хороший вариант:
SELECT CONCAT_WS(', ', street, apartment, city, country) AS full_address FROM addresses;Если все поля заполнены:
Если квартиры нет:
CONCAT_WSне оставляет строку вида:Именно поэтому его так любят для адресов, имён и человекочитаемых строк.
Сравним три способа на одной таблице
Пусть есть таблица
users:Сравним
||,CONCATиCONCAT_WS:SELECT id, first_name || ' ' || middle_name || ' ' || last_name AS via_pipes, CONCAT(first_name, ' ', middle_name, ' ', last_name) AS via_concat, CONCAT_WS(' ', first_name, middle_name, last_name) AS via_concat_ws FROM users;Результат будет примерно таким:
Что здесь произошло:
||сломался на строке с Борисом, потому чтоmiddle_nameравенNULL;CONCATне сломался, но оставил двойной пробел;CONCAT_WSдал самый аккуратный результат.Поэтому для полного имени почти всегда лучше использовать:
SELECT CONCAT_WS(' ', first_name, middle_name, last_name) AS full_name FROM users;А для адреса:
SELECT CONCAT_WS(', ', street, apartment, city, country) AS full_address FROM addresses;CONCAT и числа
Конкатенация умеет работать не только со строками. Числа и даты часто автоматически приводятся к тексту.
Например:
SELECT CONCAT('Order #', 42) AS label;Результат:
Ещё пример:
SELECT CONCAT_WS('-', 2024, 12, 31) AS date_text;Результат:
Это удобно, но есть нюанс: автоматическое преобразование не всегда даёт тот формат, который вы хотите.
Например, дата может отобразиться в одном формате в одной базе и в другом формате в другой. Число с дробной частью тоже может выглядеть не так, как нужно для интерфейса или отчёта.
Если формат важен, лучше явно управлять преобразованием.
В PostgreSQL можно так:
SELECT 'Price: ' || price::TEXT AS price_label FROM products;Для даты часто используют форматирование:
SELECT 'Date: ' || TO_CHAR(created_at, 'YYYY-MM-DD') AS created_label FROM orders;Так вы явно говорите базе: «покажи дату именно в таком виде».
Конкатенация в WHERE: почему нужно быть осторожным
Конкатенация сама по себе обычно дешёвая операция. В большинстве обычных запросов она не будет проблемой.
Но есть важный случай: не стоит бездумно склеивать поля в
WHERE.Например:
SELECT * FROM users WHERE first_name || ' ' || last_name = 'Anna Petrova';Запрос выглядит понятно, но для базы это может быть неудобно.
Если у вас есть отдельные индексы по
first_nameиlast_name, выражение со склейкой может помешать использовать их эффективно. Базе приходится сначала собрать строку, а потом сравнить её с нужным значением.Чаще лучше написать условие по отдельным колонкам:
SELECT * FROM users WHERE first_name = 'Anna' AND last_name = 'Petrova';Так базе проще использовать индексы.
Если же полное имя реально часто нужно искать или сортировать как одну строку, можно завести отдельную колонку
full_name, например вычисляемую, и индексировать уже её.Конкатенация в ORDER BY
Похожая история с сортировкой.
Можно написать так:
SELECT id, CONCAT_WS(' ', first_name, last_name) AS full_name FROM users ORDER BY CONCAT_WS(' ', first_name, last_name);Для небольших таблиц это нормально.
Но если таблица большая и такая сортировка используется часто, лучше подумать о готовом поле или функциональном индексе, если ваш диалект SQL это поддерживает.
Главная мысль простая: собрать красивую строку для вывода — нормально. Но если вы по этой строке постоянно ищете, фильтруете и сортируете, возможно, она заслуживает отдельного места в структуре данных.
Частые ошибки новичков
Ошибка 1. Использовать || и забыть про NULL
Пишут так:
SELECT first_name || ' ' || middle_name || ' ' || last_name AS full_name FROM users;А потом удивляются, почему у пользователя без отчества полное имя стало
NULL.Если поле может быть пустым, используйте
COALESCE,CONCATили лучшеCONCAT_WS.Ошибка 2. Использовать || в MySQL
В PostgreSQL такой запрос склеит строки:
SELECT 'Hello, ' || 'World' AS message;А в MySQL по умолчанию
||— это логическоеOR, а не конкатенация.Для MySQL используйте:
SELECT CONCAT('Hello, ', 'World') AS message;Если пишете код, который должен быть понятен в разных SQL-диалектах,
CONCATчасто безопаснее, чем||.Ошибка 3. Получить лишние пробелы через CONCAT
Вот такой запрос не сломается на
NULL:SELECT CONCAT(first_name, ' ', middle_name, ' ', last_name) AS full_name FROM users;Но если
middle_nameравенNULL, можно получить двойной пробел.Для полного имени лучше так:
SELECT CONCAT_WS(' ', first_name, middle_name, last_name) AS full_name FROM users;Ошибка 4. Получить лишние запятые в адресе
Новичок часто пишет:
SELECT CONCAT(street, ', ', apartment, ', ', city, ', ', country) AS full_address FROM addresses;Если
apartmentравенNULL, результат может выглядеть некрасиво:Лучше:
SELECT CONCAT_WS(', ', street, apartment, city, country) AS full_address FROM addresses;Так
NULLбудет пропущен вместе с лишней запятой.Ошибка 5. Думать, что конкатенация и сложение — одно и то же
В некоторых диалектах для строк может использоваться один оператор, в других — другой.
Например, в SQL Server оператор
+может использоваться для строк:SELECT 'Hello, ' + 'World' AS message;Но с числами
+— это уже сложение:SELECT 42 + 7 AS result;Результат будет
49, а не427.Поэтому для строк лучше использовать понятные строковые функции, например
CONCAT, особенно если вы только учитесь и не хотите путаться в особенностях диалектов.Ошибка 6. Делать CSV через простую склейку
Иногда кажется, что CSV можно собрать так:
SELECT CONCAT_WS(', ', name, city, country) AS csv_line FROM users;Для простого отображения это нормально. Но для настоящего CSV-экспорта опасно.
Если внутри значения уже есть запятая, строка может сломаться для CSV-парсера.
Например:
Простая склейка даст:
Выглядит как четыре поля вместо трёх.
Для настоящего CSV нужны экранирование, кавычки и нормальный экспортный механизм, а не просто
CONCAT_WS.Как выбрать правильный способ
Простое правило:
CONCATCONCAT_WSCONCAT_WSCONCAT_WSNULLбез лишних разделителейCONCAT_WSЕсли сомневаетесь, запомните практическую формулу:
Для человекочитаемых строк с пробелами, запятыми и необязательными полями чаще всего нужен
CONCAT_WS.Главное
Конкатенация в SQL — это склейка нескольких значений в одну строку.
Есть три популярных способа:
||— стандартный SQL-оператор, но одинNULLпревращает весь результат вNULL.CONCAT— функция склейки, которая обычно воспринимаетNULLкак пустую строку.CONCAT_WS— склейка с разделителем, которая пропускаетNULLи не оставляет лишние пробелы или запятые.Для простых строк подойдёт
CONCAT.Для имён, адресов, подписей и других строк, где часть полей может быть
NULL, чаще всего лучший выбор —CONCAT_WS.И ещё одно важное правило: склеивать строки для красивого вывода — нормально. Но если вы часто фильтруете или сортируете по склеенной строке, подумайте об отдельной колонке, вычисляемом поле или индексе. Так запросы будут не только красивыми, но и быстрыми.