如何使用 JOIN 而不是 IN 来选择一个人所属的所有组的名称?

发布于 2024-08-22 13:48:50 字数 880 浏览 5 评论 0原文

考虑以下简化示例:

CREATE TABLE groups ( gid INTEGER PRIMARY KEY, name VARCHAR(100) );

CREATE TABLE people ( pid INTEGER PRIMARY KEY );

CREATE TABLE people_groups (
    gid INTEGER NOT NULL
        CONSTRAINT fk_people_groups_group
        REFERENCES groups(gid),
    pid INTEGER NOT NULL
        CONSTRAINT fk_people_groups_person
        REFERENCES people(pid),
    CONSTRAINT pk_people_groups PRIMARY KEY (gid, pid)
);

INSERT INTO people (pid) VALUES (1);
INSERT INTO groups (gid, name) VALUES (1, 'One');
INSERT INTO groups (gid, name) VALUES (2, 'Two');
INSERT INTO people_groups (gid, pid) VALUES (1,1);
INSERT INTO people_groups (gid, pid) VALUES (2,1);

SELECT gid, name FROM groups WHERE gid IN (
    SELECT gid FROM people_groups WHERE pid = 1
);

此输出:

1|One
2|Two

最后一个 SELECT 的正确 JOIN 是什么?

Consider the following simplified example:

CREATE TABLE groups ( gid INTEGER PRIMARY KEY, name VARCHAR(100) );

CREATE TABLE people ( pid INTEGER PRIMARY KEY );

CREATE TABLE people_groups (
    gid INTEGER NOT NULL
        CONSTRAINT fk_people_groups_group
        REFERENCES groups(gid),
    pid INTEGER NOT NULL
        CONSTRAINT fk_people_groups_person
        REFERENCES people(pid),
    CONSTRAINT pk_people_groups PRIMARY KEY (gid, pid)
);

INSERT INTO people (pid) VALUES (1);
INSERT INTO groups (gid, name) VALUES (1, 'One');
INSERT INTO groups (gid, name) VALUES (2, 'Two');
INSERT INTO people_groups (gid, pid) VALUES (1,1);
INSERT INTO people_groups (gid, pid) VALUES (2,1);

SELECT gid, name FROM groups WHERE gid IN (
    SELECT gid FROM people_groups WHERE pid = 1
);

This outputs:

1|One
2|Two

What is the correct JOIN for that last SELECT?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

∞琼窗梦回ˉ 2024-08-29 13:48:50
SELECT g.gid, g.name 
  FROM groups g INNER JOIN people_groups pg
       ON g.gid = pg.gid
 WHERE pg.pid = 1

注意:这相当于您的 IN 语句,因为您专门过滤了一个人。如果您过滤多个人,情况就会有所不同。例如,假设 pid=2 的某个人也在组 1 中,并且您执行以下 SELECT:

SELECT g.gid, g.name 
  FROM groups g INNER JOIN people_groups pg
       ON g.gid = pg.gid
 WHERE pg.pid IN (1, 2)

这将返回组 1 两次(与您的 IN 解决方案相反) ,这只会返回每个组一次)。要解决这个问题,您需要在SELECT后添加DISTINCT关键字添加GROUP BY g.gid, g.name< /code> 在 SQL 的最后。如果您使用此答案作为将 IN 转换为 JOIN 的一般规则,您应该记住这一点。

SELECT g.gid, g.name 
  FROM groups g INNER JOIN people_groups pg
       ON g.gid = pg.gid
 WHERE pg.pid = 1

Note: This is equivalent to your IN statement, because you specifically filter for only one person. If you filter for multiple persons, things are different. For example, assume that some person with pid=2 is also in group 1 and you do the following SELECT:

SELECT g.gid, g.name 
  FROM groups g INNER JOIN people_groups pg
       ON g.gid = pg.gid
 WHERE pg.pid IN (1, 2)

This would return group 1 twice (in contrast to your IN solution, which would return each group only once). To solve this, you need to add the DISTINCT keyword after the SELECT or add GROUP BY g.gid, g.name at the very end of the SQL. You should keep that in mind if you use this answer as a general rule to convert IN to JOIN.

茶花眉 2024-08-29 13:48:50

这是等价的:

SELECT g.gid, g.name 
FROM groups g 
  INNER JOIN people_groups pg
  ON g.gid = pg.gid
WHERE pg.pid = 1

This is the equivalent:

SELECT g.gid, g.name 
FROM groups g 
  INNER JOIN people_groups pg
  ON g.gid = pg.gid
WHERE pg.pid = 1
破晓 2024-08-29 13:48:50
SELECT gid, name FROM groups 
NATURAL JOIN people_groups 
WHERE pid = 1;
SELECT gid, name FROM groups 
NATURAL JOIN people_groups 
WHERE pid = 1;
旧街凉风 2024-08-29 13:48:50

怎么样:

SELECT g.gid, g.name
  FROM groups AS g JOIN people_groups AS p ON g.gid = p.gid
 WHERE p.pid = 1;

How about:

SELECT g.gid, g.name
  FROM groups AS g JOIN people_groups AS p ON g.gid = p.gid
 WHERE p.pid = 1;
樱&纷飞 2024-08-29 13:48:50

之前给出的答案是正确的,但我想指出,您的查询将从在 (pid, gid) (按此顺序)上创建 PRIMARY KEY 中受益。

此查询:

SELECT  g.gid
FROM    people_groups pg
JOIN    groups g
ON      g.gid = pg.gid
WHERE   pd.pid = 1

然后能够使 people_groupsJOIN 中处于领先地位,这很可能会使速度更快,因为 pid 似乎是在链接表中非常有选择性。

或者,您可以创建辅助索引:

CREATE UNIQUE INDEX ux_peoplegroup_p_g ON people_group (pid, gid)

,或者仅

CREATE INDEX ix_peoplegroup_p ON people_group (pid)

people_groupsInnoDB 时创建。

The answers given before are correct, but I'd like to note that you query will benefit from making the PRIMARY KEY on (pid, gid) (in this order).

This query:

SELECT  g.gid
FROM    people_groups pg
JOIN    groups g
ON      g.gid = pg.gid
WHERE   pd.pid = 1

will then be able to make people_groups be leading in the JOIN which most probably will make it much faster, since pid seems to be very selective in the link table.

Alternatively, you can create a secondary index:

CREATE UNIQUE INDEX ux_peoplegroup_p_g ON people_group (pid, gid)

, or just

CREATE INDEX ix_peoplegroup_p ON people_group (pid)

if people_groups is InnoDB.

梦断已成空 2024-08-29 13:48:50
SELECT g.gid, g.name FROM groups g, people_groups pg 
WHERE g.gid = pg.gid and pg.pid = 1
SELECT g.gid, g.name FROM groups g, people_groups pg 
WHERE g.gid = pg.gid and pg.pid = 1
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文