我有两张桌子。
表-A:
id | data_x | data_y
--------------------
1 person joe
2 person bob
3 amount 200
4 addres philville
tableB的:
map_id | table_a_id
-------------------
7 1
7 3
7 4
8 4
8 2
如果data_x =' person&和data_y =' 200'
所以使用上面的表B,结果应该是
map_id
------
7
如何在SQL中编写该查询?
答案 0 :(得分:3)
这种情况非常适合不寻常的SQL运算符:INTERSECT。对于这个问题,它是一个非常具有声明性,高效和优雅的解决方案。
SELECT Map.map_id
FROM Table_B AS Map JOIN Table_A AS Person ON (Person.id = Map.table_a_id) AND (Person.data_x = 'person')
INTERSECT
SELECT Map.map_id
FROM Table_B AS Map JOIN Table_A AS Amount ON (Amount.id = Map.table_a_id) AND (Amount.data_y = '200')
正式地,你要求的是两个不相交的集合的交集:作为人的地图ID的集合和具有值200的地图id的集合。
请注意,INTERSECT运算符在MySQL中不存在,但在几乎所有高级关系DBMS中都有,包括PostgreSQL。
答案 1 :(得分:1)
根据您的输入,以下内容应该让您开始使用MySQL:
SELECT
map_id
FROM TableB
JOIN Table_A
ON TableB.table_a_id = Table_A.id
AND
((Table_A.data_x = 'person')
OR
(Table_A.data_y = '200')
)
GROUP BY map_id
HAVING COUNT(table_a_id) = 2
;
查看实际操作:SQL Fiddle。
正如Erwin Brandstetter明确指出的那样:如果不能信任数据本质上是一致的(根据您的询问),一个选项是:
SELECT map_id FROM (
SELECT map_id, 'data_x' t
FROM TableB B JOIN Table_A A ON B.table_a_id = A.id AND A.data_x = 'person'
UNION
SELECT map_id, 'data_y'
FROM TableB B JOIN Table_A A ON B.table_a_id = A.id AND A.data_y = '200'
) T
GROUP BY map_id
HAVING COUNT(DISTINCT t) = 2
;
这应该确保"每个至少一个"。 (其他人建议使用替代方案。)为了得到每个",你可以试试
SELECT map_id FROM (
SELECT map_id, 'data_x' t, data_y
FROM TableB B JOIN Table_A A ON B.table_a_id = A.id AND A.data_x = 'person'
UNION
SELECT map_id, 'data_y', data_y
FROM TableB B JOIN Table_A A ON B.table_a_id = A.id AND A.data_y = '200'
) T
GROUP BY map_id
HAVING COUNT(DISTINCT t) = 2 AND COUNT(DISTINCT data_y) = 2
;
查看实际操作(附加测试数据):SQL Fiddle。
它也适用于PostgreSQL:SQL Fiddle
请评论是否需要调整/进一步详细说明。
答案 2 :(得分:1)
这不如INTERSECT
solution @Malta posted那么优雅,但它也适用于MySQL的有限功能:
SELECT b1.map_id
FROM table_a a1
JOIN tableb b1 ON a1.id = b1.table_a_id AND a1.data_x = 'person'
JOIN tableb b2 ON b2.map_id = b1.map_id AND b2.table_a_id <> b1.table_a_id
JOIN table_a a2 ON a2.id = b2.table_a_id AND a2.data_y = '200';
答案 3 :(得分:0)
加入2个表,按map_id分组,使用带count()或sum()的条件计数,并使用having子句过滤(我使用下面的mysql语法):
select map_id,
sum(
case
when a.data_x='person' or a.data_y='200' then 1
else 0
end
) as matches
from a
inner join b on a.id=b.a_id
group by b.map_id
having matches=2
上述查询假设您不能为任何map_id拥有多条记录,其中data_x为person或data_y为200.如果此假设不正确,则您需要使用exists子查询或2个派生表。
答案 4 :(得分:0)
听起来你想要一个标准INNER JOIN
。
但我对你的结果不以为然:
map_id if it has an entry in table_a for both data_x = 'person' and data_y = '200'
您的数据集中没有包含'person'和data_y ='200'的记录,因此无法返回mp_id
以下是与您的叙述相关的典型INNER JOIN
。
SELECT DISTINCT
b.map_id
FROM
TableA a
INNER JOIN TableB b
ON a.id = b.table_a_id
WHERE
a.data_x = 'person'
AND a.data_y = '200'
如果map_id
和data_x = 'person'
存在多个data_y = '200'
,那么您将获得多个结果,但每map_id
只有一行
如果您希望map_id用于data_x = 'person'
或data_y = '200'
的记录,请将where语句中的和切换为或,您将收到map_id 7&amp; 8。
SELECT DISTINCT
b.map_id
FROM
TableA a
INNER JOIN TableB b
ON a.id = b.table_a_id
WHERE
a.data_x = 'person'
OR a.data_y = '200'
注意这包括(7,1)(8,2)因为1&amp; 2都有data_x ='person'然后是(7,3)因为3有data_y ='200'因此它将返回map_id 7&amp; 8。
答案 5 :(得分:0)
select map_id from
table_b b
left outer join table_a a1 on (b.table_a_id = a1.id and a1.data_x = 'person')
left outer join table_a a2 on (b.table_a_id = a2.id and a2.data_y = '200')
group by map_id
having count(a1.id) > 0 and count(a2.id) > 0
答案 6 :(得分:0)
让我们这么简单:
SELECT * FROM
(
SELECT map_id
FROM table_a a1
inner join TableB b1 ON a1.id = b1.table_a_id
where a1.data_x = 'person'
) as p
inner join
(
SELECT map_id
FROM table_a a1
inner join TableB b1 ON a1.id = b1.table_a_id
where a1.data_y = '200'
) as q
on p.map_id = q.map_id
您可以将SELECT * FROM
替换为SELECT p.map_id FROM
您可以添加更多子集连接以获得更多条件。
sql-fiddle