在PostgreSQL中,我想使用SQL语句组合两列并从中创建一个新列。
我正在考虑使用concat(...)
,但是有更好的方法吗?
最好的方法是什么?
答案 0 :(得分:66)
一般来说,我同意@kgrittn's advice。去吧。
但要解决有关concat()
的基本问题:如果您需要处理空值,则新函数concat()
非常有用 - 并且null中既没有排除你的问题也不是你提到的问题。
如果可以排除空值,那么旧的(SQL标准)连接运算符||
仍然是最佳选择,@luis' answer就可以了:
SELECT col_a || col_b;
如果您的任何一列都可以为null,那么在这种情况下结果将为null。您可以使用COALESCE
进行辩护:
SELECT COALESCE(col_a, '') || COALESCE(col_b, '');
但随着更多的争论,这会很快变得乏味。这就是concat()
进来的地方,从不返回null,即使所有参数都为null也不行。 Per documentation:
忽略NULL参数。
SELECT concat(col_a, col_b);
两种备选方案的剩下的大小写是 所有输入列为空,在这种情况下,我们仍然会得到一个空字符串{{1但是,有人可能想要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)
的简写表示法。如果所有列为null,则行类型仅为null。详细解释:
另外,使用concat_ws()
在元素(ROW (col_a, col_b)
..“和分隔符”之间添加分隔符。)
表达式与凯文的答案相似:
_ws
在PostgreSQL 8.3(没有SELECT $1.zipcode || ' - ' || $1.city || ', ' || $1.state;
)中准备空值是很繁琐的。一种方式(很多):
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
)在区域设置上。 Explanation by Tom Lane.
这禁止将它们直接用于索引表达式。如果知道结果在您的情况下实际上是不可变的,您可以使用timestamptz_out
函数包装器解决此问题。示例:
答案 1 :(得分:15)
您无需存储列以便以此方式引用它。试试这个:
设置:
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首先检查实际列,但是如果找不到一个,并且标识符用关系名称或别名限定,它会查找类似上面的函数,并以行作为其运行它参数,返回结果,好像它是一个列。如果您愿意,您甚至可以在这样的“生成列”上编制索引。
因为您没有在每行中为重复数据使用额外空间,或者在所有插入和更新上触发触发器,所以这通常比替代方案更快。
答案 2 :(得分:12)