1

鉴于此架构:

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满足超过 1 个关系的行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.ids :IN

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 小提琴

4

2 回答 2

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
于 2013-01-22T11:55:30.627 回答
2

我可能会过度简化问题,但是您能否在 where 子句中将an 更改AND为 an并用于获取给定条件的关系数。例如ORGROUP BY/HAVING

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)
于 2013-01-22T11:57:37.190 回答