如何在Postgres SELECT语句中连接列?

218

我在表foo中有两个字符串列ab

select a, b from foo 返回ab的值。然而,ab的连接并不起作用。我尝试了:

select a || b from foo

select  a||', '||b from foo

评论更新:两列都是类型character(2)


...或者另一个text类型? - PM 77-1
1
@acfrancis,由于OP说“连接”,我怀疑他处理的不是数字类型,尽管PostgreSQL也会处理其中的一些。请参见这里:http://www.postgresql.org/docs/9.1/static/functions-string.html - PM 77-1
1
是的,这些列是character(2)类型。"+"符号不起作用 - "没有匹配给定名称和参数类型的运算符。您可能需要添加显式类型转换。" - Alex
1
PostgreSQL的哪个版本?这里是9.1的文档:http://www.postgresql.org/docs/9.1/static/functions-string.html。请看我的示例:http://sqlfiddle.com/#!15/d41d8/182 - PM 77-1
你的查询语句可能存在语法错误,与连接无关。 - PM 77-1
请具体说明。当您说“不起作用”时,是什么意思?请提供错误消息和完整的原始SQL。此外,“character”是一种糟糕的数据类型,请尽可能避免使用它,而选择使用“varchar”或“text”。 - Craig Ringer
9个回答

351

对于像您稍后提到的character(2)这样的字符串类型,显示连接仅起作用是因为根据手册所述:

[...] 字符串连接运算符(||)接受非字符串输入,只要至少有一个输入是字符串类型,如表9.8所示。对于其他情况,请插入显式强制转换为text [...]

这里强调是我的。第二个示例(select a||', '||b from foo)对于任何数据类型都有效,因为未经过类型定义的字符串文字', '默认为类型text,使整个表达式在任何情况下都有效。

对于非字符串数据类型,您可以通过将至少一个参数转换text来“修复”第一个语句。(任何类型都可以强制转换为text):

SELECT a::text || b AS ab FROM foo;

你自己的回答来看,"does not work"的意思应该是"返回NULL"。将任何东西与NULL连接的结果都是NULL。如果涉及到NULL值,并且结果不应该是NULL,请使用concat_ws()连接任意数量的值(Postgres 9.1或更高版本):

SELECT concat_ws(', ', a, b) AS ab FROM foo;

分隔符仅在非空值之间添加,即仅在必要时添加。

或者如果您不需要分隔符,可以使用 concat() 函数:

SELECT concat(a, b) AS ab FROM foo;

这里不需要类型转换,因为两个函数都接受"any"输入,并且使用文本表示。

有关更多详细信息(以及为什么COALESCE是一个糟糕的替代品),请参见此相关回答:

关于在注释中的更新

+不是Postgres(或标准SQL)中用于字符串连接的有效运算符。这是微软将其添加到其产品的私有想法。

几乎没有什么好理由使用character(n)(同义词:char(n))。使用textvarchar。详情如下:


谢谢。第一版无法处理空值,第二版在使用concat_ws时出现错误:没有匹配给定名称和参数类型的函数。您可能需要添加显式类型转换。 - Alex
1
你确实看到了 Postgres 9.1 或更高版本,对吧? 你一开始就应该在问题中提供你的Postgres版本。 请在回来提问之前更新你的问题,包括所有请求的信息。 - Erwin Brandstetter
谢谢,我找到的解决方案适用于任何Postgres版本。 - Alex
abVARCHAR类型时,SELECT concat(a, b) FROM foo;在Postgres 9.3中对我有效。 - elimisteve

49
问题在于数值中的空值; 然后如果有空值进行拼接会失败。解决方法如下:
SELECT coalesce(a, '') || coalesce(b, '') FROM foo;

31

在PostgreSQL中,最好使用CONCAT函数进行字符串拼接。

例如:select CONCAT(first_name,last_name) from person where pid = 136

如果您使用column_a || ' ' || column_b来连接2列,如果column_a或column_b的值为空,则查询将返回空值。这可能不是所有情况下都希望发生的。所以,可以用CONCAT替代||符号。

||

改为使用

CONCAT

如果它们中有任何一个具有值,则会返回相关值。


3
对我有用。很高兴发现我可以在“太”之间添加一个空格: CONCAT(first_name,' ',last_name) - Neil Gaetano Lindberg
这应该是正确的答案,因为concat接受null。 - Cocuba

14

我也陷入了同样的困境,我觉得我应该分享对我最有效的解决方案。我也认为这更简单。

如果您使用大写表名。

SELECT CONCAT("firstName", ' ', "lastName") FROM "User"

如果您使用小写表名

SELECT CONCAT(firstName, ' ', lastName) FROM user

就是这样!由于PGSQL在列声明中计算双引号,而在字符串中计算单引号,因此这非常顺利。


如果存在NULL值,该表达式会产生前导或尾随空格。通常不是您想要的。请改用concat_ws() - Erwin Brandstetter

12

在较旧版本的postgreSQL中,CONCAT函数有时无法正常工作。

看看我用来解决问题而不使用CONCAT的方法

 u.first_name || ' ' || u.last_name as user,

或者你也可以使用

 "first_name" || ' ' || "last_name" as user,
在第二种情况下,我在 first_name 和 last_name 上使用了双引号。
希望这对你有用,谢谢。

1
如果我的名字或姓氏为空,则连接值也显示为空。 - Lokesh

0

PHP的Laravel框架, 我正在使用搜索first_name、last_name字段,考虑像全名搜索一样

使用||符号或concat_ws()、concat()方法

$names = str_replace(" ", "", $searchKey);                               
$customers = Customer::where('organization_id',$this->user->organization_id)
             ->where(function ($q) use ($searchKey, $names) {
                 $q->orWhere('phone_number', 'ilike', "%{$searchKey}%"); 
                 $q->orWhere('email', 'ilike', "%{$searchKey}%");
                 $q->orWhereRaw('(first_name || last_name) LIKE ? ', '%' . $names. '%');
    })->orderBy('created_at','desc')->paginate(20);

这个完美运行了!!!


-1

试试这个

select concat_ws(' ', FirstName, LastName) AS Name from person;

9
concat_ws(' ', FirstName, LastName) 更清晰简洁。 - user330315

-2
例如,如果有一个员工表,其中包含以下列:
employee_number,f_name,l_name,email_id,phone_number 

如果我们想要将f_name + l_name连接成name
SELECT employee_number,f_name ::TEXT ||','|| l_name::TEXT  AS "NAME",email_id,phone_number,designation FROM EMPLOYEE;

这个答案相比现有的答案有什么新的补充? - Erwin Brandstetter

-2

你也可以使用管道进行此操作。

Select EmployeeID ,FirstName ||' ' || LastName as Full_Name from Employees
order by EmployeeID

这并没有回答问题,也没有添加任何有用的内容。 - Erwin Brandstetter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接