左连接返回重复的行

Posted

技术标签:

【中文标题】左连接返回重复的行【英文标题】:Left join returns duplicate rows 【发布时间】:2018-12-12 09:51:32 【问题描述】:

我刚刚学习 SQL,我真的很难理解为什么我的。这是我正在使用的查询:

SELECT "id", "title"
FROM "posts"
LEFT JOIN "comments" "comment"
ON "comment"."post_id"="id" AND ("comment"."status" = 'hidden')

它返回 4 行,但应该只返回 3。返回的两个行包含重复(相同的值)。我可以通过在"id" 上使用DISTINCT 前缀来解决此问题。

SELECT DISTINCT "id", "title"
FROM "posts"
LEFT JOIN "comments" "comment"
ON "comment"."post_id"="id" AND ("comment"."status" = 'hidden')

查询返回 3 行,我得到了想要的结果。但是我仍然想知道为什么我首先会从第一个查询中得到重复的行?我正在尝试编写一个聚合查询,这似乎是我遇到的问题。

我正在使用 PostgreSQL。

更具体: (由我的 ORM 创建)

转移 DDL

CREATE TABLE shift (
    id uuid DEFAULT uuid_generate_v4() PRIMARY KEY,
    "gigId" uuid REFERENCES gig(id) ON DELETE CASCADE,
    "categoryId" uuid REFERENCES category(id),
    notes text,
    "createdAt" timestamp without time zone NOT NULL DEFAULT now(),
    "updatedAt" timestamp without time zone NOT NULL DEFAULT now(),
    "salaryFixed" numeric,
    "salaryHourly" numeric,
    "salaryCurrency" character varying(3) DEFAULT 'SEK'::character varying,
    "staffingMethod" character varying(255) NOT NULL DEFAULT 'auto'::character varying,
    "staffingIspublished" boolean NOT NULL DEFAULT false,
    "staffingActivateon" timestamp with time zone,
    "staffingTarget" integer NOT NULL DEFAULT 0
);

ShiftEmployee DDL

CREATE TABLE "shiftEmployee" (
    "employeeId" uuid REFERENCES employee(id) ON DELETE CASCADE,
    "shiftId" uuid REFERENCES shift(id) ON DELETE CASCADE,
    status character varying(255) NOT NULL,
    "updatedAt" timestamp without time zone NOT NULL DEFAULT now(),
    "salaryFixed" numeric,
    "salaryHourly" numeric,
    "salaryCurrency" character varying(3) DEFAULT 'SEK'::character varying,
    CONSTRAINT "PK_6acfd2e8f947cee5a62ebff08a5" PRIMARY KEY ("employeeId", "shiftId")
);

查询

SELECT "id", "staffingTarget" FROM "shift" LEFT JOIN "shiftEmployee" "se" ON "se"."shiftId"="id" AND ("se"."status" = 'confirmed');

结果

id                                      staffingTarget
68bb0892-9bce-4d08-b40e-757cb0889e87    3
12d88ff7-9144-469f-8de5-3e316c4b3bbd    6
73c65656-e028-4f97-b855-43b00f953c7b    5
68bb0892-9bce-4d08-b40e-757cb0889e88    3
e3279b37-2ba5-4f1d-b896-70085f2ba345    4
e3279b37-2ba5-4f1d-b896-70085f2ba346    5
e3279b37-2ba5-4f1d-b896-70085f2ba346    5
789bd2fb-3915-4cda-a3d7-2186cf5bb01a    3

【问题讨论】:

向我们展示一些示例表数据和预期结果 - 都是格式化文本,而不是图像。 我添加了更多关于实际案例的信息 你真的应该避免那些可怕的带引号的标识符。 DISTINCTSELECT DISTINCT 的一部分 - 并且适用于整个选定的行,而不仅仅是 ID 列。 我来自 JS 星球,所以我应该更多地研究 SQL。感谢您的建议,aHorseWithNoName。 【参考方案1】:

如果帖子有多个隐藏评论,您将多次看到该帖子,因为加入会为每次匹配返回一行 - 这就是加入的本质。外连接的行为并没有什么不同。

如果您的意图是仅列出带有隐藏 cmets 的帖子,最好使用 EXISTS 查询:

SELECT p.id, p.title
FROM posts p
where exists (select *
              from comments c 
              where c.post_id = p.id 
                and c.status = 'hidden');

【讨论】:

我现在明白每次连接都会返回一行,我认为更像是对象。我正在尝试group by p.idselect p.id, SUM(p.price), COUNT(c)(分组帖子并计算隐藏的 cmets)。也许超出了问题的范围,但如果您有任何建议,我将不胜感激。

以上是关于左连接返回重复的行的主要内容,如果未能解决你的问题,请参考以下文章

如何与第一个匹配行左连接并用空填充其余部分?

数据库操作-内连接外连接

限制在 MySQL 问题的左连接中返回的行

左连接在查询后返回更多和更少的行

外连接查询

使用左连接的查询返回的行数较少