首页 > 解决方案 > 错误:OR 的参数不能返回一个集合

问题描述

在这里运行 PostgreSQL 9.2.8...

我一直在尝试获取地址中包含非 ASCII 字符的表中所有行的列表 - 范围之外的任何内容<space>to~以及反引号字符`。如果任何行包含任何无效字符,则将显示具有所有地址值的行。但由于某种原因,我收到以下错误:

ERROR:  argument of OR must not return a set (10586)
LINE 9: (CAST(regexp_matches(a.address_line_1,'([^ !-~]|`)') AS VARCHAR)...
         ^

********** Error **********

ERROR: argument of OR must not return a set (10586)
SQL state: 42804
Character: 252

我一直在尝试使用的查询如下:

select a.address_id, a.address_line_1, 
    a.address_line_2, 
    a.address_line_3, 
regexp_matches(a.address_line_1,'([^ !-~]|`)'),
regexp_matches(a.address_line_2,'([^ !-~]|`)'),
regexp_matches(a.address_line_3,'([^ !-~]|`)')
    FROM public.address a 
WHERE 
(CAST(regexp_matches(a.address_line_1,'([^ !-~]|`)') AS VARCHAR) <> '') OR
(CAST(regexp_matches(a.address_line_2,'([^ !-~]|`)') AS VARCHAR) <> '') OR
(CAST(regexp_matches(a.address_line_3,'([^ !-~]|`)') AS VARCHAR) <> '')
LIMIT 1000

我不确定我可能会丢失什么,因为这似乎是一个有效的查询。

我正在尝试获取三个地址字段中的任何一个中存在无效字符的行,而不仅仅是三个地址字段中的无效字符。

标签: sqlregexpostgresqlnon-ascii-characters

解决方案


regexp_matches()返回SETOF text并且不能像您尝试的那样使用(正如错误消息告诉您的那样)。您可以改用正则表达式运算符~

但是您的正则表达式似乎没有涵盖您所描述的内容:

地址中的非 ASCII 字符

此外,!-~括号表达式中的范围[^ !-~]取决于您的COLLATION设置。手册警告:

范围非常依赖于排序序列,因此可移植程序应避免依赖它们。

考虑:

SELECT g, chr(g), chr(g) ~ '([^ !-~]|`)'
FROM   generate_series (1,300) g;  -- ASCII range plus some

假设服务器编码 UTF8,要在 3 列中查找具有任何非 ASCII 字符的行:

...
WHERE octet_length(concat(a.address_line_1, a.address_line_2, a.address_line_3))
         <> length(concat(a.address_line_1, a.address_line_2, a.address_line_3))

这是因为所有非 ASCII 字符在 UTF8 中都用超过 1 个字节编码,因此octet_length()报告的数字高于length()(别名:)char_length()。与concat()防止可能的 NULL 值的连接。

要同时测试反引号,请添加:

...
OR  concat(a.address_line_1, a.address_line_2, a.address_line_3) LIKE '%`%'

推荐阅读