38

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

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

4

3 回答 3

90

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

但是要解决您的基本问题:如果您需要处理null 值concat(),则新函数很有用-并且 null 在您的问题和您所指的问题中都没有被排除。concat()

如果您可以排除空值,那么旧的(SQL 标准)连接运算符||仍然是最佳选择,@luis 的回答很好:

SELECT col_a || col_b;

如果您的任何一列可以为空,则在这种情况下结果将为空。您可以使用以下方法进行辩护COALESCE

SELECT COALESCE(col_a, '') || COALESCE(col_b, '');

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

NULL 参数被忽略。

SELECT concat(col_a, col_b);

两种选择的剩余极端情况是所有输入列都是 null在这种情况下我们仍然得到一个空 string '',但可能需要 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;

随着更多列的增加,这会变得更加复杂。再次,使用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;

concat()在 PostgreSQL 8.3(没有)中准备空值是很乏味的。一种方式(多种方式):

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函数包装器解决此问题。这里的例子:

于 2012-09-07T14:45:06.223 回答
17

您无需存储该列即可以这种方式引用它。试试这个:

建立:

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 - 纽约州纳努埃 |
+---------+--------+--------+--------+

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

因为您没有在每行中为重复数据使用额外空间,也没有在所有插入和更新上触发触发器,所以这通常比其他方法更快。

于 2012-09-07T03:23:41.367 回答
16

您是否检查了字符串连接功能?就像是:

update table_c set column_a = column_b || column_c 

应该管用。更多在这里

于 2012-09-07T02:49:58.810 回答