具有两个EXISTS语句的SQL查询的行为与预期不同

时间:2017-10-27 03:46:54

标签: sql postgresql

以下SQL查询旨在查找label_item_lists,其中label_items具有给定名称。

  SELECT lils.id FROM label_item_lists AS lils
  INNER JOIN label_items AS items ON lils.id = items.label_item_list_id
  WHERE EXISTS(SELECT * FROM label_item_lists WHERE items.name=?)
  OR EXISTS(SELECT * FROM label_item_lists WHERE items.name=?)

它正确返回具有任一名称的项目的label_item_lists的id。但是,使用AND运算符而不是OR的相同查询不会返回任何结果。

  SELECT lils.id FROM label_item_lists AS lils
  INNER JOIN label_items AS items ON lils.id = items.label_item_list_id
  WHERE EXISTS(SELECT * FROM label_item_lists WHERE items.name=?)
  AND EXISTS(SELECT * FROM label_item_lists WHERE items.name=?)

肯定有label_item_list条目,其label_items与提供的两个名称相匹配。事实上,OR SQL查询为这些条目返回两次id,但AND查询不返回任何结果。出于这个原因,我想我可能会错过关于这些JOINed查询如何与EXISTS一起工作的重要信息。谢谢你的帮助!

----------------------------------------------------------------
|  label_items     | id        | name      | label_item_list_id |
----------------------------------------------------------------
| Row1             | 1         | foo       | 1                  |
----------------------------------------------------------------
| Row2             | 2         | bar       | 1                  |
----------------------------------------------------------------
| Row3             | 3         | bar       | 2                  |
----------------------------------------------------------------


--------------------------------
| label_item_lists | id        | 
--------------------------------
| Row1             | 1         | 
--------------------------------
| Row2             | 2         |
--------------------------------

我想要返回第一个label_item_list而不是第二个,因为它只有我正在搜索的两个名称中的一个,'foo'和'bar'。

3 个答案:

答案 0 :(得分:0)

尝试从

更改where条件
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>SimpleWidget</title>
    <base href="">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="icon" type="image/x-icon" href="favicon.ico">
    <link href="styles.d41d8cd98f00b204e980.bundle.css" rel="stylesheet"/>
</head>
<body>
<app-root></app-root>
<app-root></app-root>
<app-root></app-root>
<app-root></app-root>
<app-root></app-root>
<app-root></app-root>
<script type="text/javascript" src="inline.12e8db88bf510206182f.bundle.js"></script>
<script type="text/javascript" src="polyfills.35726d60cdf25fecc5f1.bundle.js"></script>
<script type="text/javascript" src="vendor.4ec6f75eb1fd6ed6bd56.bundle.js"></script>
<script type="text/javascript" src="main.db9607812bd105b9d1c8.bundle.js"></script>
</body>
</html>

index.html

答案 1 :(得分:0)

在你的查询中并且不会返回任何内容,因为在同一输出行上它将应用两个永远不会发生的过滤器,因此它会给出空白输出。 并且OR运算符永远不会在OR运算符之后检查条件,直到第一个条件为假。

尝试这样的事情,@只是一个区分两个搜索的占位符:

select * from label_items lil
where label_item_list_id 
in (
select li.label_item_list_id   from 
label_items li 
inner join label_items l1
on li.label_item_list_id = l1.label_item_list_id
and li.name <> l1.name
where concat(li.name,'@',l1.name) = 'foo@bar')

答案 2 :(得分:0)

这是我最终想出来的!我还没有100%的自信,但到目前为止它已经奏效了。我在Ruby和ActiveRecord中添加了一些功能,以允许根据需要进行尽可能多的必要匹配,并仅返回那些完全匹配的(没有列表中没有任何额外名称)。

  items = ["foo", "bar"]
  db = ActiveRecord::Base.connection

  query = <<-EOS
    SELECT lils.id FROM label_item_lists AS lils
    JOIN label_items AS items ON items.label_item_list_id = lils.id
    WHERE lils.id IN (
      SELECT label_item_list_id FROM label_items AS items
      WHERE items.name IN (#{(['?'] * items.length).join(',')})
    ) AND lils.id NOT IN (
      SELECT label_item_list_id FROM label_items AS items
      WHERE items.name NOT IN (#{(['?'] * items.length).join(',')})
    )
    GROUP BY lils.id
    HAVING COUNT(DISTINCT items.name) = #{items.length}
  EOS

  query = ActiveRecord::Base.send(:sanitize_sql_array, [query, *(items*2)])

基本上它检查名称是否在给定名称列表中(项目数组)并且它还检查名称是否在给定名称列表之外(或不是IN)。后一个IN查询排除任何具有不匹配名称的label_items列表。这很有用,因此不包括同时包含“foo”和“bar”以及“lorem”的label_item_list。