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

bsxbgnwa  于 2023-03-12  发布在  PostgreSQL
关注(0)|答案(4)|浏览(121)

我试图获取这样的行,其中text[]类型的列包含类似于某个用户输入的值。
到目前为止,我所考虑和做的是像这样使用'ANY''LIKE '运算符:

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

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

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

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

为什么LIKE操作符不能与ANY操作符一起工作,并且我没有得到任何错误?我认为一个原因应该是ANY操作符在查询的右边,但是...

是否有任何不使用unnest()的解决方案,以及WHERE子句中是否可能?

guicsvcw

guicsvcw1#

ANY*不是 * 运算符,而是只能用于运算符 * 右侧 * 的SQL构造。详细信息:

  • 如何在WHERE子句中使用ANY代替IN?

LIKE运算符--或者更准确地说:* 关键字 *,在Postgres内部重写为~~运算符-期望左边的 value 和右边的 pattern。这个运算符没有COMMUTATOR(就像简单的相等运算符=一样),所以Postgres不能翻转操作数。
您的尝试:

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

...左右操作数反向。'%someInput%'value,数组列someColum的元素被视为模式,这不是您想要的。
它 * 应该 * 是类似 * ANY (someColum) LIKE '%someInput%' * 的东西--但是ANY结构只允许放在操作符的 * 右边 *。
相关:

  • 有没有一种方法可以有效地索引包含正则表达式模式的文本列?
  • PostgreSQL可以索引数组列吗?

您可以规范化关系设计,并将数组的 elements 保存在单独表的单独行中。除此之外,**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中的特殊字符进行转义。请参阅:

  • 正则表达式或LIKE模式的转义函数
    小心在可能涉及NULL时使用否定(NOT LIKE ALL (...)):
  • 检查Postgres数组中是否存在NULL
6mzjoqzu

6mzjoqzu2#

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

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

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

643ylb08

643ylb083#

我的question被一个粗心的mod标记为重复并链接到一个断章取义的问题。这个问题与我问的最接近,所以我在这里留下我的答案。(我认为这可能会帮助人们了解unnest()是一个解决方案)
在我的例子中,DISTINCTunnest()的组合是解决方案:

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

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

更新

另一种在WHERE子句中不使用DISTINCT的方法是:

SELECT *
FROM someTable 
WHERE (
  0 < (
    SELECT COUNT(*) 
    FROM unnest(tags) AS tag
    WHERE tag LIKE '%someInput%'
  )
);
tvmytwxo

tvmytwxo4#

拜托。
这个答案正是我要找的。它还提供了一些有用的提示(和示例),以防您需要更多的灵活性。
它基本上解释了ANY()、**@〉&&**操作符。

  • “如果要搜索多个值,可以使用@〉运算符”*
  • "@〉表示包含该数组中的所有值。如果要搜索当前数组是否包含其他数组中的任何值,可以使用&&"*

相关问题