【问题标题】:Check if value exists in Postgres array检查 Postgres 数组中是否存在值
【发布时间】:2012-06-29 04:48:02
【问题描述】:

使用 Postgres 9.0,我需要一种方法来测试给定数组中是否存在值。到目前为止,我想出了这样的事情:

select '{1,2,3}'::int[] @> (ARRAY[]::int[] || value_variable::int)

但我一直认为应该有一个更简单的方法,我只是看不到它。这似乎更好:

select '{1,2,3}'::int[] @> ARRAY[value_variable::int]

我相信这就足够了。但如果你有其他方法,请分享!

【问题讨论】:

    标签: sql arrays postgresql


    【解决方案1】:

    ANY 结构更简单:

    SELECT value_variable = ANY ('{1,2,3}'::int[])
    

    ANY 的右操作数(括号之间)可以是set (result of a subquery, for instance)array。有几种使用方法:

    重要区别:Array operators (<@, @>, && et al.) 期望 array 类型作为操作数,support GIN or GiST indices 在 PostgreSQL 的标准发行版中,而 ANY 构造期望 element 类型作为左操作数并且不支持这些索引。示例:

    这些都不适用于NULL 元素。测试NULL

    【讨论】:

    • 谢谢。一定跳过了手册的那部分。这很好用。它具有自动铸造的副作用。例如: SELECT 1::smallint = ANY ('{1,2,3}'::int[]) 有效。只需确保将 ANY() 放在表达式的右侧即可。
    • 感谢您的回答。我的查询在本地工作时遇到问题,但在 heroku 中抛出此消息 ANY/ALL (array) requires array on right side::int[] 的添加起到了作用。
    • where S.employee_id
    • 虽然这是互联网时代的恐龙问题,但像我这样的慢人应该知道'something' = ANY(some_array)也可以在WHERE子句中使用。由于只有 Crom 知道的原因,我在过去的四年中一直认为我不能在 WHERE 子句中使用数组比较器。那些日子现在已经一去不复返了。 (我小时候被摔在头上,所以也许只有我一个人)。
    • @GT.:它的要点:any boolean 表达式在 WHERE 子句中起作用 - Crom 愿意。
    【解决方案2】:

    当心我陷入的陷阱:当检查某个值是否存在于数组中时,你不应该这样做:

    SELECT value_variable != ANY('{1,2,3}'::int[])
    

    但使用

    SELECT value_variable != ALL('{1,2,3}'::int[])
    

    改为。

    【讨论】:

    • 双重否定;注意他使用ALL vs ANY
    • SELECT NOT value_variable = ANY('{1,2,3}'::int[]) 可能更具可读性
    【解决方案3】:

    但如果您有其他方法,请分享。

    您可以比较两个数组。如果左侧数组中的任何值与右侧数组中的值重叠,则返回 true。这有点骇人听闻,但确实有效。

    SELECT '{1}'   && '{1,2,3}'::int[];  -- true
    SELECT '{1,4}' && '{1,2,3}'::int[];  -- true
    SELECT '{4}'   && '{1,2,3}'::int[];  -- false
    
    • 在第一个和第二个查询中,值1 在正确的数组中
    • 请注意,第二个查询是 true,即使值 4 不包含在正确的数组中
    • 对于第三个查询,左侧数组(即4)中没有值在右侧数组中,因此返回false

    【讨论】:

    • 如何从另一个表中搜索列以在数组中包含值?例如select * from beers where style_id in (select preferences from users where id=1) limit 1; style_id 是整数数据类型;首选项是整数 [] 我收到此错误错误:运算符不存在:整数 = 整数 [] 第 1 行:从啤酒中选择 * 其中 style_id 在(选择首选项 f... ^ 提示:没有运算符与给定的名称和参数类型匹配(s)。您可能需要添加显式类型转换。
    • @HP 有不同的方法可以解决这个问题,你应该问一个新问题
    • 您确定没有现有问题吗? @vol7ron
    • @HP 完全没有,但 cmets 是针对有关问题或答案的 cmets;通常是添加更多信息或征求更多未解决的信息。您提出的问题与此答案无关。我认为通过将您的问题作为新帖子而不是在评论中提出来,您会获得更多的运气;)
    • @HP 如果您尚未发布您的问题,您可以在此处查看:sqlfiddle.com/#!15/144cd/3 以了解您需要做什么的示例——您的问题有所不同,因为您需要取消嵌套阵列。
    【解决方案4】:

    unnest 也可以使用。 它将数组扩展为一组行,然后简单地检查一个值是否存在,就像使用 INNOT IN 一样简单。

    例如

    1. id => uuid

    2. exception_list_ids => uuid[]

    select * from table where id NOT IN (select unnest(exception_list_ids) from table2)

    【讨论】:

    • 是的。请注意,在我的查询计划中,SELECT UNNEST 不如 = ANY。我建议检查查询计划,看看你是否得到了你想要/期望的结果。
    【解决方案5】:

    你好,这个对我来说很好,也许对某人有用

    select * from your_table where array_column ::text ilike ANY (ARRAY['%text_to_search%'::text]);
    

    【讨论】:

      【解决方案6】:

      在数组中查找元素是否存在时,需要正确转换才能通过 postgres 的 SQL 解析器。下面是一个在连接子句中使用数组包含运算符的示例查询:

      为简单起见,我只列出相关部分:

      table1 other_name text[]; -- is an array of text
      

      显示的 SQL 的连接部分

      from table1 t1 join table2 t2 on t1.other_name::text[] @> ARRAY[t2.panel::text]
      

      以下也有效

      on t2.panel = ANY(t1.other_name)
      

      我只是猜测需要额外的转换,因为解析不必获取表定义来确定列的确切类型。其他人请对此发表评论。

      【讨论】:

        【解决方案7】:

        “任何”效果很好。只需确保 any 关键字位于等号的右侧,即出现在等号之后。

        下面的语句会抛出错误:ERROR: syntax error at or near "any"

        select 1 where any('{hello}'::text[]) = 'hello';
        

        而下面的例子工作正常

        select 1 where 'hello' = any('{hello}'::text[]);
        

        【讨论】:

          猜你喜欢
          • 2016-04-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-06-22
          • 2020-08-03
          • 1970-01-01
          相关资源
          最近更新 更多