Объедините два столбца и добавьте в один новый столбец.
В PostgreSQL я хочу использовать оператор SQL для объединения двух столбцов и создания из них нового столбца.
Я думаю об использовании concat(...)
, но есть ли лучший способ?
Какой лучший способ сделать это?
3 ответа
В общем, я согласен с советом @kgrittn. Действуй.
Но чтобы ответить на ваш основной вопрос о concat()
: Новая функция concat()
полезно, если вам нужно иметь дело со значениями NULL - и NULL не исключено ни в вашем вопросе, ни в том, на который вы ссылаетесь.
Если вы можете исключить нулевые значения, старый добрый (стандарт SQL) оператор конкатенации ||
все еще лучший выбор, и ответ @luis очень хорош:
SELECT col_a || col_b;
Если любой из ваших столбцов может быть нулевым, в этом случае результат будет нулевым. Вы могли бы защитить с COALESCE
:
SELECT COALESCE(col_a, '') || COALESCE(col_b, '');
Но это быстро становится утомительным с большим количеством аргументов. Это где concat()
приходит, который никогда не возвращает ноль, даже если все аргументы нулевые. По документации:
Пустые аргументы игнорируются.
SELECT concat(col_a, col_b);
Оставшийся угловой случай для обеих альтернатив - это когда все входные столбцы равны нулю, и в этом случае мы все еще получаем пустую строку ''
, но можно вместо этого хотеть ноль (по крайней мере, я бы хотел). Один из возможных способов:
SELECT CASE
WHEN col_a IS NULL THEN col_b
WHEN col_b IS NULL THEN col_a
ELSE col_a || col_b
END
Это становится более сложным с большим количеством столбцов быстро. Опять же, используйте concat()
но добавьте проверку для специального условия:
SELECT CASE WHEN (col_a, col_b) IS NULL THEN NULL
ELSE concat(col_a, col_b) END;
Как это работает? (col_a, col_b)
является сокращенной записью для выражения типа строки ROW (col_a, col_b)
, И тип строки является только нулевым, если все столбцы являются нулевыми. Детальное объяснение:
Также используйте concat_ws()
добавить разделители между элементами (_ws
.. "с разделителем").
Выражение, похожее на выражение в ответе Кевина:
SELECT $1.zipcode || ' - ' || $1.city || ', ' || $1.state;
утомительно готовить нулевые значения в PostgreSQL 8.3 (без concat()
). Один из способов (из многих):
SELECT COALESCE(
CASE
WHEN $1.zipcode IS NULL THEN $1.city
WHEN $1.city IS NULL THEN $1.zipcode
ELSE $1.zipcode || ' - ' || $1.city
END, '')
|| COALESCE(', ' || $1.state, '');
Функция волатильности только STABLE
Обратите внимание, однако, что concat()
а также concat_ws()
являются STABLE
функции, а не IMMUTABLE
потому что они могут вызывать функции вывода типа данных (например, timestamptz_out
), которые зависят от настроек локали. Объяснение Тома Лейна.
Это запрещает их прямое использование в выражениях индекса. Если вы знаете, что результат на самом деле является неизменным в вашем случае, вы можете обойти это с помощью IMMUTABLE
функциональная обертка. Пример здесь:
Вам не нужно хранить столбец, чтобы ссылаться на него таким образом. Попробуй это:
Установить:
CREATE TABLE tbl
(zipcode text NOT NULL, city text NOT NULL, state text NOT NULL);
INSERT INTO tbl VALUES ('10954', 'Nanuet', 'NY');
Мы можем видеть, что у нас есть "правильные вещи":
\pset border 2
SELECT * FROM tbl;
+ --------- + -------- + ------- + | почтовый индекс | город | состояние | +---------+--------+-------+ | 10954 | Нануэт | Нью-Йорк | + --------- + -------- + ------- +
Теперь добавьте функцию с нужным "именем столбца", которая принимает тип записи таблицы в качестве единственного параметра:
CREATE FUNCTION combined(rec tbl)
RETURNS text
LANGUAGE SQL
AS $$
SELECT $1.zipcode || ' - ' || $1.city || ', ' || $1.state;
$$;
Это создает функцию, которую можно использовать, как если бы это был столбец таблицы, если указано имя таблицы или псевдоним, например:
SELECT *, tbl.combined FROM tbl;
Который отображается так:
+ --------- + -------- + ------- + -------------------- + | почтовый индекс | город | состояние | комбинированный | +---------+--------+-------+--------------------+ | 10954 | Нануэт | Нью-Йорк | 10954 - Nanuet, NY | +---------+--------+-------+--------------------+
Это работает, потому что PostgreSQL сначала проверяет фактический столбец, но если он не найден, а идентификатор квалифицируется именем отношения или псевдонимом, он ищет функцию, подобную приведенной выше, и запускает ее со строкой в качестве аргумента, возвращая результат, как если бы это был столбец. Вы можете даже индексировать такой "сгенерированный столбец", если хотите.
Поскольку вы не используете дополнительное пространство в каждой строке для дублированных данных или запускаете триггеры на всех вставках и обновлениях, это часто может быть быстрее, чем альтернативы.
Вы проверяли функцию конкатенации строк? Что-то вроде:
update table_c set column_a = column_b || column_c
должно сработать. Больше здесь