选择具有多个关系的行

时间:2013-01-22 11:51:14

标签: sql postgresql

鉴于此架构:

CREATE TABLE t (
  id int,
  name varchar(200),
  primary key (id)
);

CREATE TABLE t2 (
  id int,
  name varchar(200),
  primary key (id)
);

CREATE TABLE rel (
  id1 int,
  id2 int,
  value int,
  primary key (id1, id2),
  foreign key (id1) REFERENCES t(id),
  foreign key (id2) REFERENCES t2(id)
);

如何查询t中与t2有多个关系的行? 这听起来很容易,但我不确定在这种情况下最佳做法是什么。我会用查询更好地解释:

SELECT t.id, t.name
FROM t
INNER JOIN rel ON (t.id = rel.id1)
INNER JOIN t2 ON (t2.id = rel.id2)
WHERE (rel.id2 = 1 AND rel.value = 1)

当我需要找到满足一个关系的行时,上面的工作很好。但现在:

SELECT t.id, t.name
FROM t
INNER JOIN rel ON (t.id = rel.id1)
INNER JOIN t2 ON (t2.id = rel.id2)
WHERE (rel.id2 = 1 AND rel.value = 1)
AND (rel.id2 = 2 AND rel.value = 2)

使用2个关系时,此查询将永远不会起作用,因为连接的行在一行中永远不会有2个不同的关系,因此它将始终返回0行。

我到目前为止使用的解决方案是查找t.idIN来自关系的结果集:

SELECT t.id, t.name
FROM t
WHERE (t.id IN (SELECT id1 FROM rel WHERE rel.id2 = 1 AND rel.value = 1))
AND (t.id IN (SELECT id1 FROM rel WHERE rel.id2 = 2 AND rel.value = 2))

这有效,但是没有更好的方法吗?我觉得我写的SQL太多了,为每个项目做一个子查询似乎有点过分了。

这是SQL Fiddle

2 个答案:

答案 0 :(得分:2)

这称为关系部门。

SELECT   t.id, t.name
FROM     t 
         INNER JOIN rel
            ON t.id = rel.id1
WHERE    rel.id2 IN (1,2) AND
         rel.value = 1
GROUP BY t.id, t.name
HAVING   COUNT(rel.id2) = 2

答案 1 :(得分:2)

我可能过度简化了问题,但是你不能在where子句中将AND更改为OR并使用GROUP BY/HAVING来获取给定条件的关系数量。 e.g。

SELECT  t.id, t.name
FROM    t
        INNER JOIN rel 
            ON t.id = rel.id1
        INNER JOIN t2 
            ON t2.id = rel.id2
WHERE   (rel.id2 = 1 AND rel.value = 1)
OR      (rel.id2 = 2 AND rel.value = 1)
GROUP BY t.Id, t.Name
HAVING COUNT(*) = 2;

虽然我会将where子句重写为:

WHERE   rel.Value = 1 
AND     rel.ID2 IN (1, 2)

修改

我不会再用编辑过的问题重写上面的where子句。它会成为

WHERE   (rel.id2 = 1 AND rel.value = 1)
OR      (rel.id2 = 2 AND rel.value = 2)