Как объединить строки в SQL

Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.

Зачем нужно объединять строки

Два частых сценария. Первый — склейка строк в одной записи: first_name + ' ' + last_namefull_name. Второй — агрегация по группе: собрать все теги пользователя в одну строку через запятую.

На собесе спрашивают оба варианта. Junior знает только CONCAT. Middle знает STRING_AGG (Postgres) или GROUP_CONCAT (MySQL) для группирующей агрегации. Senior обсудит NULL-behavior, разделители, sorting внутри агрегата.

В статье — все способы:

  • CONCAT / || — простая склейка
  • STRING_AGG в Postgres
  • GROUP_CONCAT в MySQL
  • LISTAGG в Oracle / Snowflake
  • Работа с NULL
  • Сортировка внутри агрегата

1. CONCAT — простая склейка

-- Postgres, MySQL, MSSQL
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users;

-- Postgres alt: ||
SELECT first_name || ' ' || last_name AS full_name FROM users;

NULL handling

-- Postgres / MSSQL: || с NULL → NULL для всего
SELECT 'Hello ' || NULL || ' World';  -- NULL

-- CONCAT пропускает NULL
SELECT CONCAT('Hello ', NULL, ' World');  -- 'Hello  World'

-- для защиты — COALESCE
SELECT 'Hello ' || COALESCE(name, '') || ' World';

2. CONCAT_WS — с разделителем

-- Postgres, MySQL
SELECT CONCAT_WS(' ', first_name, middle_name, last_name) AS full_name
FROM users;
-- 'John Edward Smith'
-- автоматически пропускает NULL

3. STRING_AGG в Postgres

Агрегация строк в группе:

SELECT
    user_id,
    STRING_AGG(tag, ', ') AS all_tags
FROM user_tags
GROUP BY user_id;

Результат:

user_id | all_tags
1       | vip, premium, early-adopter
2       | free, new

С сортировкой

STRING_AGG(tag, ', ' ORDER BY tag) AS tags_sorted

С distinct

STRING_AGG(DISTINCT tag, ', ' ORDER BY tag)

4. GROUP_CONCAT в MySQL

SELECT
    user_id,
    GROUP_CONCAT(tag SEPARATOR ', ') AS all_tags
FROM user_tags
GROUP BY user_id;

С сортировкой:

GROUP_CONCAT(tag ORDER BY tag SEPARATOR ', ')

С distinct:

GROUP_CONCAT(DISTINCT tag ORDER BY tag SEPARATOR ', ')

Лимит длины

В MySQL default лимит 1024 символа. Увеличить:

SET SESSION group_concat_max_len = 1000000;

5. LISTAGG (Oracle, Snowflake)

SELECT
    user_id,
    LISTAGG(tag, ', ') WITHIN GROUP (ORDER BY tag) AS all_tags
FROM user_tags
GROUP BY user_id;

6. Практика: список товаров в заказе

SELECT
    o.order_id,
    STRING_AGG(
        p.name || ' (x' || oi.quantity || ')',
        ', '
        ORDER BY p.name
    ) AS items_summary
FROM orders o
JOIN order_items oi ON oi.order_id = o.order_id
JOIN products p ON p.id = oi.product_id
GROUP BY o.order_id;

Результат:

order_id | items_summary
1001     | Apple (x2), Bread (x1), Milk (x3)

7. Склеить emails через запятую

Для email-кампании:

SELECT STRING_AGG(email, ', ') AS email_list
FROM users
WHERE is_subscribed;

8. Теги как массив → строка

-- массив ['a', 'b', 'c'] → 'a,b,c'
SELECT ARRAY_TO_STRING(tags, ',') FROM posts;

9. Multi-column aggregation

Собрать все имена и возрасты в одной строке:

SELECT
    country,
    STRING_AGG(name || ' (' || age || ')', ', ' ORDER BY age DESC) AS people
FROM users
GROUP BY country;

10. JSON alternative

Вместо склейки — иногда лучше JSON:

-- Postgres
SELECT
    user_id,
    JSON_AGG(tag ORDER BY tag) AS tags_json
FROM user_tags
GROUP BY user_id;
-- ["premium", "vip"]

Для dashboard / API ответа удобнее.

Частые ошибки

1. GROUP_CONCAT лимит

В MySQL по умолчанию 1024. На больших группах — данные обрезаются. Увеличивайте group_concat_max_len.

2. || с NULL

В Postgres 'a' || NULL → NULL. Защищайтесь через COALESCE.

3. Порядок случайный без ORDER BY

Без сортировки теги могут идти в разном порядке. Для детерминизма — ORDER BY.

4. Дубликаты

Без DISTINCT один тег будет повторяться. STRING_AGG(DISTINCT tag, ',').

Связанные темы

FAQ

STRING_AGG в старом Postgres?

Доступен с 9.0. Если старше — array_to_string(array_agg(tag), ',').

В ClickHouse?

groupArray → массив, потом arrayStringConcat(arr, ',').

GROUP_CONCAT с LIMIT?

Не напрямую. Через subquery с LIMIT до агрегации.

В BigQuery?

STRING_AGG(tag, ', ' ORDER BY tag) — синтаксис аналогичен Postgres.


Тренируйте SQL — откройте тренажёр с 1500+ вопросами для собесов.