合并两列并添加到一个新列中

Roc*_*ock 31 sql postgresql null concatenation

在PostgreSQL中,我想使用SQL语句组合两列并从中创建一个新列.

我正在考虑使用concat(...),但有更好的方法吗?
最好的方法是什么?

Erw*_*ter 68

一般来说,我同意@ kgrittn的建议.去吧.

但是要解决你的基本问题concat():concat()如果你需要处理空值,新函数很有用- 并且在你的问题和你引用的问题中都没有排除null.

如果你可以排除空值,那么好的(SQL标准)连接运算符||仍然是最好的选择,@ luis的答案就好了:

SELECT col_a || col_b;
Run Code Online (Sandbox Code Playgroud)

如果您的任何一列都可以为null,那么在这种情况下结果将为null.你可以用COALESCE:

SELECT COALESCE(col_a, '') || COALESCE(col_b, '');
Run Code Online (Sandbox Code Playgroud)

但随着更多的争论,这会很快变得乏味.这就是concat()进来的地方,即使所有参数都为null ,它也永远不会返回null.每个文件:

NULL参数被忽略.

SELECT concat(col_a, col_b);
Run Code Online (Sandbox Code Playgroud)

两个备选方案的剩余角落情况所有输入列都为null,在这种情况下我们仍然得到一个空字符串'',但是可能需要null(至少我会).一种可能的方式:

SELECT CASE
          WHEN col_a IS NULL THEN col_b
          WHEN col_b IS NULL THEN col_a
          ELSE col_a || col_b
       END;
Run Code Online (Sandbox Code Playgroud)

随着更多列的快速变得越来越复杂.再次使用,concat()但添加一个检查特殊条件:

SELECT CASE WHEN (col_a, col_b) IS NULL THEN NULL
            ELSE concat(col_a, col_b) END;
Run Code Online (Sandbox Code Playgroud)

这是如何运作的?
(col_a, col_b)是行类型表达式的简写表示法ROW (col_a, col_b).如果所有列都为null,则行类型仅为null.详细说明:

另外,用于concat_ws()在元素之间添加分隔符(ws.."with separator").


像凯文的回答一样的表达:

SELECT $1.zipcode || ' - ' || $1.city || ', ' || $1.state;
Run Code Online (Sandbox Code Playgroud)

在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, '');
Run Code Online (Sandbox Code Playgroud)

功能波动只是 STABLE

但是请注意,这concat()concat_ws()STABLE功能,而不是IMMUTABLE因为他们可以调用的数据类型的输出函数(如timestamptz_out依赖于区域设置).汤姆莱恩的解释.

这禁止它们直接用于索引表达式.如果你知道结果在你的情况下实际上是不可变的,你可以使用IMMUTABLE函数包装器解决这个问题.这里的例子:


kgr*_*ttn 15

您不需要存储列以便以这种方式引用它.试试这个:

建立:

CREATE TABLE tbl
  (zipcode text NOT NULL, city text NOT NULL, state text NOT NULL);
INSERT INTO tbl VALUES ('10954', 'Nanuet', 'NY');
Run Code Online (Sandbox Code Playgroud)

我们可以看到我们有"正确的东西":

\pset border 2
SELECT * FROM tbl;
Run Code Online (Sandbox Code Playgroud)
+---------+--------+-------+
| zipcode |  city  | state |
+---------+--------+-------+
| 10954   | Nanuet | NY    |
+---------+--------+-------+

现在添加一个具有所需"列名"的函数,该函数将表的记录类型作为其唯一参数:

CREATE FUNCTION combined(rec tbl)
  RETURNS text
  LANGUAGE SQL
AS $$
  SELECT $1.zipcode || ' - ' || $1.city || ', ' || $1.state;
$$;
Run Code Online (Sandbox Code Playgroud)

这创建了一个函数,可以像使用表的列一样使用它,只要指定了表名或别名,如下所示:

SELECT *, tbl.combined FROM tbl;
Run Code Online (Sandbox Code Playgroud)

哪个显示如下:

+---------+--------+-------+--------------------+
| zipcode |  city  | state |      combined      |
+---------+--------+-------+--------------------+
| 10954   | Nanuet | NY    | 10954 - Nanuet, NY |
+---------+--------+-------+--------------------+

这是因为PostgreSQL首先检查实际列,但是如果找不到一个,并且标识符用关系名称或别名限定,它会查找类似上面的函数,并以行作为参数运行它,返回结果好像是一个列.如果您愿意,您甚至可以在这样的"生成列"上编制索引.

因为您没有在每行中为重复数据使用额外空间,或者在所有插入和更新上触发触发器,所以这通常比备选方案更快.


lui*_*uis 13

你检查了字符串连接功能吗?就像是:

update table_c set column_a = column_b || column_c 
Run Code Online (Sandbox Code Playgroud)

应该管用.更多这里