仅当所有连接条件都匹配时,Oracle才会返回行

时间:2016-03-18 08:56:41

标签: sql oracle

http://sqlfiddle.com/#!4/bab93d

请参阅SQL小提琴示例...我有客户,标签和映射表。我试图通过标签实现客户搜索,它必须是AND搜索。查询将传递一个标记标识符列表(任意数字),并且只能返回包含所有标记的客户。

在示例中,我使用了一个IN运算符,但它对应于OR搜索并且没有解决我的问题。查询应该是什么样的AND搜索?

select
  *
from
  customer c
  inner join customer_tag ct on ct.customer_id = c.customer_id
where
  ct.tag_id in (1, 2);

这将返回两个客户,但只有第一个客户被标记为标记1和2。

4 个答案:

答案 0 :(得分:3)

您可以使用相关子查询来获取所有客户的列表:

SELECT  *
FROM  customer c
WHERE c.customer_ID IN
(
     SELECT customer_id
     FROM customer_tag ct
     WHERE ct.customer_id = c.customer_id
       AND ct.tag_id IN (1,2)
     GROUP BY customer_id
     HAVING COUNT(DISTINCT tag_id) = 2
);  

LiveDemo

很容易扩展:

WHERE ct_tag IN (1,2,3)
...
HAVING COUNT(DISTINCT tag_id) = 3

答案 1 :(得分:3)

JOIN版本:

SELECT c.*
FROM  customer c
JOIN (SELECT customer_id
      FROM customer_tag
      WHERE tag_id IN (1,2)
      GROUP BY customer_id
      HAVING MAX(tag_id) <> MIN(tag_id)) ct ON c.customer_id = ct.customer_id

如果您有两个以上不同的值,请改用COUNT DISTINCT,如下所示:

SELECT c.*
FROM  customer c
JOIN (SELECT customer_id
      FROM customer_tag
      WHERE tag_id IN (1,2,3)
      GROUP BY customer_id
      HAVING COUNT(DISTINCT tag_id) = 3) ct ON c.customer_id = ct.customer_id

答案 2 :(得分:1)

您可以执行类似

的操作
SELECT *
FROM customer c
WHERE 
  2 = (SELECT COUNT(DISTINCT ct.tag_id) 
       FROM customer_tag ct 
       WHERE ct.customer_id = c.customer_id AND ct.tag_id IN (1, 2));

2 = ...部分应根据您要搜索的代码数量进行调整。

替代解决方案 - 相关子查询可能性能较差,因此您可以加入像这样的表

SELECT c.*
FROM customer c
  INNER JOIN (
    SELECT ct.customer_id
    FROM customer_tag ct
    WHERE ct.tag_id IN (1, 2)
    GROUP BY ct.customer_id
    HAVING COUNT(DISTINCT ct.tag_id) = 2
  ) ct ON ct.customer_id = c.customer_id;

答案 3 :(得分:1)

扩展其他答案,我将添加一个版本,您不需要计算标签,也不需要列出两次:

WITH tgs as(
   select distinct tag_id
   from Tags
   where tag_id in (1, 2, 3, 4) --modify only here
) 
SELECT c.*
FROM  customer c
JOIN (SELECT customer_id
      FROM customer_tag
      WHERE tag_id in (select tag_id from tgs)
      GROUP BY customer_id
      HAVING COUNT(DISTINCT tag_id) = (select count(*) from tgs)
     ) ct ON c.customer_id = ct.customer_id

如果表格正确规范化(并且有pks等),您可以删除distinct个关键字。