Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 选择两个数组的元素与模式不匹配的行_Sql_Arrays_Postgresql_Unnest - Fatal编程技术网

Sql 选择两个数组的元素与模式不匹配的行

Sql 选择两个数组的元素与模式不匹配的行,sql,arrays,postgresql,unnest,Sql,Arrays,Postgresql,Unnest,我尝试编写一个查询,其中我基于一个相似的模式选择行,该模式必须与数组的任何条目都不匹配。我所拥有的是现在的 SELECT * FROM mytable WHERE NOT (EXISTS (SELECT * from unnest(a) WHERE unnest LIKE '%XYZ%' ))) 实际上,我想要的是成对的,所以它更像 SELECT * FROM mytable WHERE NOT ( (EXISTS (select * from unnest(a) as A, un

我尝试编写一个查询,其中我基于一个相似的模式选择行,该模式必须与数组的任何条目都不匹配。我所拥有的是现在的

SELECT * FROM mytable WHERE 
NOT (EXISTS (SELECT * from unnest(a) WHERE  unnest LIKE '%XYZ%' ))) 
实际上,我想要的是成对的,所以它更像

SELECT * FROM mytable WHERE 
NOT (
  (EXISTS (select * from unnest(a) as A, unnest(b) as B  WHERE  A||B LIKE '%xyz%abc%' )) OR
  (EXISTS (select * from unnest(a) as A, unnest(b) as B  WHERE  A||B LIKE '%abc%xyz%' ))
)
这对我来说很有效,但看起来相当笨拙。是否有更漂亮/更有效的解决方案?我发现最令人讨厌的是WHERE子句中用于展开数组的SELECT as部分

有几点:

在我的情况下,xyz和abc不会作为子字符串一起出现在单个数组条目中,例如,与xyzblaabcexists不同 两个数组的元素数完全相同,它们实际上是从另一个查询派生的 没有空元素,但即使它仍然可以工作,因为我没有一对abc和xyz 编辑:

澄清:一行包含a as{rxyz,foo,bar}和B as{other,abc,this}不应返回,因为它在一个数组中包含rxyz,在另一个数组中包含abc

例如:

SELECT * FROM(
 SELECT *
    FROM   (select 1 as ID, '{rxyz,foo,bar}'::varchar[] as a, '{abc,other,this}'::varchar[] as b) row1  UNION
 SELECT *
    FROM   (select 2 as ID, '{rxyz,foo,bar}'::varchar[] as a, '{other,rabc,this}'::varchar[] as b) row1  UNION
 SELECT *
    FROM   (select 3 as ID, '{else,foo,bar}'::varchar[] as a, '{abc,other,this}'::varchar[] as b) row2

    ) mytable
WHERE   
NOT (
  (EXISTS (select * from unnest(a) as A, unnest(b) as B  WHERE  A||'-|-'||B LIKE '%xyz%-|-%abc%' OR B||'-|-'||A LIKE '%xyz%-|-%abc%' )))

仅返回第3行。在我的用例中,我可以保证-|-不属于这两个列表的一部分,因此可以将它们分开。

您可以将这两个列表都取消到一个派生表中:

select *
from mytable
where not exists (select *
                  from unnest(a,b) as x(a,b)
                  where x.a like '%xyz%'
                     or x.b like '%xyz%'
                     or x.a like '%abc%'
                     or x.b like '%abc%')

更新后的任务描述为:

消除文本数组a的任何元素包含“abc”、“xyz”和文本数组b的任何元素包含另一个元素的行

您的第二个查询实现了这一点,但代价很高。unnesta作为A,unnestb将数组A的每个元素与数组b的每个元素组合在一起-笛卡尔积在²上会使较长数组的性能迅速恶化

请尝试以下方法之一:

针对具有交叉联接的连接字符串进行测试:

确保选择的分隔符不能产生错误匹配。“|”在这个例子中

针对不存在的连接字符串进行测试:

使用横向子查询测试未列出的元素

SELECT t.*
FROM   tbl t
JOIN   LATERAL (
   SELECT bool_or(a_elem LIKE '%abc%') AND bool_or(b_elem LIKE '%xyz%') 
       OR bool_or(a_elem LIKE '%xyz%') AND bool_or(b_elem LIKE '%abc%') AS exclude
   FROM   unnest(t.a,t.b) e(a_elem, b_elem)
   ) x ON exclude IS NOT TRUE;
测试不存在的未列出元素

小提琴

最后一个是我最喜欢的。我不知道哪一个表现最好。所有这些都应该比你现在的表现快很多

关于unnesta,b:

对你的观点有一些评论 在我的情况下,xyz和abc不会作为子字符串一起出现在单个数组条目中,例如,与xyzblaabcexists不同

这是一个很大的假设。这可能有很好的理由,但你确定没有角落案件,现在没有,永远没有?否则,您的代码将在稍后悄无声息地中断,并且很难确定原因

两个数组的元素数完全相同,它们实际上是从另一个查询派生的

最有效的查询通常是在源位置应用过滤器,如果可能的话,在另一个查询中应用过滤器。甚至可以使用适当的索引。例如,三元索引:

没有空元素,但即使它仍然可以工作,因为我没有一对abc和xyz


很公平。但是,如果有空值,请注意空值会做您想做的事情。

*这是有效的…-还是这样?请看答案。所以,在中,只有1-3个符合条件?@ErwinBrandstetter在中,除4之外的所有内容都应返回。抱歉,这不符合要求。应用于fiddle的查询返回一个不同的集合:dbfiddle请提供您想要实现的目标的精确定义。@ErwinBrandstetter如我所述,abc和xyz将不属于同一个字符串。在你的例子中,它们出现在7和8中——对不起,我错过了。因此,4、7和8被正确地过滤掉。这些数组实际上是其他数据上的数组_agg的结果。所以我知道它们的尺寸总是一样的。我对我想要的做了一些澄清-sorry@Lutz:我写了一个新的答案来解决这个问题。实际上,我希望的是用一些更简洁易读的东西来取代整个不存在的东西,比如x的倒数,比如任何条件数组。我想我必须坚持下去。至于在源代码处应用-在这里不起作用。因此,类似于“%xyz%”和“%abc%”的任何a和任何b,或者类似“%xyz%”的任何b和类似“%abc%”的任何a,我所能想到的只是子代码中不存在-querry@Lutz当前位置请在中答复我的请求。我答案顶部的假设正确吗?当问题还不完全清楚时,很难讨论细节。谢谢-我不知道unesta,b。
SELECT *
FROM   tbl t
WHERE  NOT EXISTS (
   SELECT FROM array_to_string(a, '|') a_string
             , array_to_string(b, '|') b_string
   WHERE  a_string LIKE '%abc%' AND b_string LIKE '%xyz%'
      OR  a_string LIKE '%xyz%' AND b_string LIKE '%abc%'
   );
SELECT t.*
FROM   tbl t
JOIN   LATERAL (
   SELECT bool_or(a_elem LIKE '%abc%') AND bool_or(b_elem LIKE '%xyz%') 
       OR bool_or(a_elem LIKE '%xyz%') AND bool_or(b_elem LIKE '%abc%') AS exclude
   FROM   unnest(t.a,t.b) e(a_elem, b_elem)
   ) x ON exclude IS NOT TRUE;
SELECT *
FROM   tbl t
WHERE  NOT EXISTS (
   SELECT FROM unnest(t.a,t.b) AS e(a_elem, b_elem)
   HAVING bool_or(a_elem LIKE '%abc%') AND bool_or(b_elem LIKE '%xyz%') 
       OR bool_or(a_elem LIKE '%xyz%') AND bool_or(b_elem LIKE '%abc%')
   );