查找文本数组包含与输入类似的值的行

Find rows where text array contains value similar to input

提问人:Jose Hermosilla Rodrigo 提问时间:1/7/2016 最后编辑:Erwin BrandstetterJose Hermosilla Rodrigo 更新时间:3/10/2023 访问量:24498

问:

我正在尝试获取类型列包含类似于某些用户输入的值的行。text[]

到目前为止,我所想和所做的是像这样使用 and ' 运算符:'ANY''LIKE

select * from someTable where '%someInput%' LIKE ANY(someColum);

但它不起作用。查询返回的值与此查询相同:

select * from someTable where 'someInput' = ANY(someColum);

我在子查询中使用该函数得到了很好的结果,但如果可能的话,我需要在子句中查询这个。unnest()WHERE

为什么操作员不与操作员一起工作,而我没有收到任何错误?我认为一个原因应该是运算符在查询的右侧,但是......LIKEANYANY

在不使用的情况下是否有任何解决方案,如果在子句中可能的话?unnest()WHERE

数组 postgresql sql-like any unnest

评论

3赞 1/7/2016
不使用的解决方案是正确地规范化数据模型。unnest
0赞 Jose Hermosilla Rodrigo 1/7/2016
如果没有任何其他解决方案,我想创建一个新表而不是此数据类型的列。我会做的,所以!感谢您的回答!

答:

24赞 Erwin Brandstetter 1/7/2016 #1

ANY不是运算符,而是一个只能在运算符右侧使用的 SQL 构造。更多:

运算符 - 或者更准确地说:关键字,在 Postgres 内部重写给运算符 - 期望在左边,模式在右边。此运算符没有 COMMUTATOR(就像简单相等运算符一样),因此 Postgres 无法翻转操作数。LIKE~~=

您的尝试:

select * from someTable where '%someInput%' LIKE ANY(someColum);

...有左右操作数向后。 是数组列的值,并且数组列的元素被视为模式,这不是您想要的。'%someInput%'someColum

它必须类似于 ANY (someColum) LIKE '%someInput%' - 但构造只允许在运算符的右侧。你遇到了一个路障。ANY

相关:

您可以规范化关系设计,并将数组的元素保存在单独表中的单独行中。除此之外,unnest() 是解决方案,正如您已经找到的那样。但是,虽然您只对至少一个匹配元素的存在感兴趣,但 EXISTS 子查询将是最有效的,并且可以避免结果中的重复。Postgres 可以在找到第一个匹配项后立即停止搜索:

SELECT *
FROM   tbl
WHERE  EXISTS (
    SELECT -- SELECT list can be empty for this purpose
    FROM   unnest(someColum) elem
    WHERE  elem LIKE '%someInput%'
  );

您可能希望对 中的特殊字符进行转义。看:someInput

当可能涉及否定 () 时,请小心NOT LIKE ALL (...)NULL

评论

0赞 Jose Hermosilla Rodrigo 1/7/2016
谢谢你的信息!!
8赞 Rotareti 5/10/2018 #2

的问题被标记为重复,并被一个粗心的模组断章取义地链接到一个问题。这个问题最接近我问的问题,所以我把我的答案留在这里。(我认为它可能会帮助人们解决)unnest()

就我而言,和的组合是解决方案:DISTINCTunnest()

SELECT DISTINCT ON (id_) *
FROM (
  SELECT unnest(tags) tag, *
  FROM someTable
  ) x
WHERE (tag like '%someInput%');

unnest(tags)将文本数组展开为行列表,并基于唯一列删除扩展产生的重复项。DISTINCT ON (id_)id_

更新

另一种在没有子句的情况下执行此操作的方法是:DISTINCTWHERE

SELECT *
FROM someTable 
WHERE (
  0 < (
    SELECT COUNT(*) 
    FROM unnest(tags) AS tag
    WHERE tag LIKE '%someInput%'
  )
);
10赞 GoldDragonTSU 6/12/2018 #3

一个公认的不完美的可能性可能是使用ARRAY_TO_STRING,然后对结果使用。例如:LIKE

SELECT *
FROM someTable
WHERE ARRAY_TO_STRING(someColum, '||') LIKE '%someInput%';

但是,这种方法可能会有问题,因为如果有人发现连接字符序列,他们可能会搜索两个数组元素。例如,如果用户输入了 代替 ,则连接的数组 将返回结果。相反,人们的期望可能是在这种情况下不会有结果,因为既不包含字符序列,也不单独包含字符序列。{'Hi','Mom'}||i||MsomeInputHiMomi||M

0赞 Javi 5/15/2020 #4

检查一下

这个答案正是我想要的。它还提供了一些有用的提示(和示例),以防您需要更大的灵活性。

它基本上解释了 ANY()、@>&& 运算符。

“如果要搜索多个值,可以使用 @> 运算符”

“@> 表示包含该数组中的所有值。如果要搜索当前数组是否包含另一个数组中的任何值,可以使用 &&”