在 PostgreSQL 中,我想使用 SQL 语句来组合两列并从中创建一个新列。
我正在考虑使用concat(...)
,但有更好的方法吗?
最好的方法是什么?
在 PostgreSQL 中,我想使用 SQL 语句来组合两列并从中创建一个新列。
我正在考虑使用concat(...)
,但有更好的方法吗?
最好的方法是什么?
一般来说,我同意@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
函数包装器解决此问题。这里的例子:
您无需存储该列即可以这种方式引用它。试试这个:
建立:
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 首先检查一个实际的列,但如果没有找到,并且标识符用关系名称或别名限定,它会查找类似上面的函数,并以行作为参数运行它,返回结果就好像它是一列一样。如果您愿意,您甚至可以对这样的“生成的列”进行索引。
因为您没有在每行中为重复数据使用额外空间,也没有在所有插入和更新上触发触发器,所以这通常比其他方法更快。