[英]Oracle return rows only if all join conditions match
http://sqlfiddle.com/#!4/bab93d http://sqlfiddle.com/#!4/bab93d
See the SQL Fiddle example... I have Customers, Tags, and a mapping table. 请参阅SQL小提琴示例...我有客户,标签和映射表。 I am trying to implement customer search by tags, and it has to be an AND search. 我试图通过标签实现客户搜索,它必须是AND搜索。 The query is passed a list of tag identifiers (any number), and it has to return only customers that have ALL the tags. 查询将传递一个标记标识符列表(任意数字),并且只能返回包含所有标记的客户。
In the example I have used an IN operator, but that corresponds to an OR search and doesn't solve my problem. 在示例中,我使用了一个IN运算符,但它对应于OR搜索并且不能解决我的问题。 What should the query look like to be an AND search? 查询应该是什么样的AND搜索?
select
*
from
customer c
inner join customer_tag ct on ct.customer_id = c.customer_id
where
ct.tag_id in (1, 2);
This returns both customers, but only the first customer is tagged with tag 1 and 2. 这将返回两个客户,但只有第一个客户标记有标记1和2。
You could use correlated subquery to get list of all customers: 您可以使用相关子查询来获取所有客户的列表:
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
);
It is easy to extend just: 它很容易扩展:
WHERE ct_tag IN (1,2,3)
...
HAVING COUNT(DISTINCT tag_id) = 3
JOIN
version: 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
If you have more than 2 different values, use COUNT DISTINCT
instead, like this: 如果您有两个以上的不同值,请使用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
You could do something like 你可以做点什么
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));
The 2 = ...
part should be adjusted according to the number of tags you are trying to search for. 2 = ...
部分应根据您尝试搜索的标签数量进行调整。
Alternative solution - correlated subqueries can have poor performance, so you could join in a table like this 替代解决方案 - 相关子查询可能性能较差,因此您可以加入这样的表
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;
Extending the other answers, I will add a version where you don't need to count the tags nor list them twice: 扩展其他答案,我将添加一个版本,您不需要计算标签,也不需要列出两次:
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
If the tables are rightly normalized(and have pks, etc) you can remove the distinct
keywords. 如果表格正确规范化(并具有pks等),则可以删除distinct
关键字。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.