【发布时间】:2012-08-31 22:00:36
【问题描述】:
在 PostgreSQL 中,我想使用 SQL 语句来组合两列并从中创建一个新列。
我正在考虑使用concat(...),但有更好的方法吗?
最好的方法是什么?
【问题讨论】:
标签: sql postgresql null concatenation
在 PostgreSQL 中,我想使用 SQL 语句来组合两列并从中创建一个新列。
我正在考虑使用concat(...),但有更好的方法吗?
最好的方法是什么?
【问题讨论】:
标签: sql postgresql null concatenation
总的来说,我同意@kgrittn's advice。去吧。
但要解决您关于 concat() 的基本问题:如果您需要处理 null 值,新功能 concat() 很有用 - 您的问题和你指的那个。
如果可以排除空值,那么旧的(SQL 标准)连接运算符|| 仍然是最佳选择,而@luis' answer 就好了:
SELECT col_a || col_b;
如果您的任一列可以为空,则在这种情况下,结果将为空。你可以用COALESCE防守:
SELECT COALESCE(col_a, '') || COALESCE(col_b, '');
但是随着参数的增加,这很快就会变得乏味。这就是concat() 的用武之地,它从不 返回null,即使所有 参数都为null。 Per documentation:
NULL 参数被忽略。
SELECT concat(col_a, col_b);
两种备选方案的剩余极端情况是所有输入列为空在这种情况下,我们仍然会得到一个空字符串'' ,但有人可能想要 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) 的简写符号。只有当 all 列为空时,行类型才为空。详细解释:
另外,使用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)。
Explanation by Tom Lane.
这禁止它们在索引表达式中直接使用。如果您知道在您的情况下结果实际上是不可变的,您可以使用IMMUTABLE 函数包装器来解决这个问题。此处示例:
【讨论】:
|| 连接运算符的不同 NULL 处理。 (您注意到我在回答中使用NOT NULL 列避开了这个问题。)我现在的工具箱中多了一个工具。
您无需存储该列即可以这种方式引用它。试试这个:
设置:
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 首先检查一个实际的列,但如果没有找到,并且标识符是用关系名称或别名限定的,它会查找类似上面的函数,并以行作为它的运行它参数,将结果作为列返回。如果您愿意,您甚至可以对这样的“生成的列”进行索引。
因为您没有在每行中为重复数据使用额外空间,或者在所有插入和更新时触发触发器,所以这通常比其他方法更快。
【讨论】:
which takes the record type of the table as its only parameter" : 创建表后如何发现?
CREATE TABLE tbl 和CREATE FUNCTION combined(rec tbl)。对于确定的答案,找到表的 pg_class 行的 reltype 列,并使用它来找到匹配的 pg_type 行。
【讨论】: