如何在SQL中完成以下操作?

时间:2016-07-09 23:25:46

标签: mysql sql postgresql

我有两张桌子。

表-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中编写该查询?

7 个答案:

答案 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';

SQL Fiddle for MySQL.
SQL Fiddle for Postgres.

答案 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_iddata_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