В PostgreSQL я хочу использовать оператор SQL для объединения двух столбцов и создания из них нового столбца.
Я думаю об использовании concat(...)
, но есть ли лучший способ?
Какой лучший способ сделать это?
В PostgreSQL я хочу использовать оператор SQL для объединения двух столбцов и создания из них нового столбца.
Я думаю об использовании concat(...)
, но есть ли лучший способ?
Какой лучший способ сделать это?
Как правило, я согласен с @kgrittn advice. Пойти на это.
Но чтобы ответить на ваш основной вопрос о concat()
: новая функция concat()
полезна, если вам нужно иметь дело с нулевыми значениями - и в вашем вопросе не исключено ни одно из них. ни в том, на который вы ссылаетесь.
Если вы можете исключить нулевые значения, то старый добрый (стандарт 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;
+---------+--------+-------+ | zipcode | city | state | +---------+--------+-------+ | 10954 | Nanuet | NY | +---------+--------+-------+
Теперь добавьте функцию с нужным "именем столбца", который принимает тип записи таблицы как единственный параметр:
CREATE FUNCTION combined(rec tbl)
RETURNS text
LANGUAGE SQL
AS $$
SELECT $1.zipcode || ' - ' || $1.city || ', ' || $1.state;
$$;
Это создает функцию, которая может использоваться как столбец таблицы, если указано имя таблицы или псевдоним, например:
SELECT *, tbl.combined FROM tbl;
Отображается следующим образом:
+---------+--------+-------+--------------------+ | zipcode | city | state | combined | +---------+--------+-------+--------------------+ | 10954 | Nanuet | NY | 10954 - Nanuet, NY | +---------+--------+-------+--------------------+
Это работает, потому что PostgreSQL сначала проверяет фактический столбец, но если он не найден, а идентификатор имеет имя отношения или псевдоним, он ищет функцию, подобную приведенной выше, и запускает ее со строкой как ее аргумент, возвращая результат, как если бы это был столбец. Вы можете даже индексировать такой "сгенерированный столбец", если хотите это сделать.
Поскольку вы не используете дополнительное пространство в каждой строке для дублированных данных или запускаете триггеры во всех вставках и обновлениях, это часто может быть быстрее, чем альтернативы.
Вы проверили функцию конкатенации строк? Что-то вроде:
update table_c set column_a = column_b || column_c
должен работать. Подробнее здесь