INNER JOIN和GROUP BY可防止重复结果

时间:2015-09-30 15:53:08

标签: mysql orm group-by

上下文:

我正在开发一个简单的ORM(用于PHP),它基于静态配置自动化大多数查询。

因此,从表和实体定义中,库自动处理连接并生成适当的字段/表别名......对于LEFT连接没有问题,但是对于一对多关系,INNER可能会导致重复的结果。 我的想法是在必要时自动添加GROUP BY子句(在自动增量键上)。

问题

如果(并且仅当)连接的ON和WHERE条件与连接表的唯一键不匹配,我认为需要添加GROUP BY子句是否正确?

实施例

一个非常简单的例子,我想用(至少)一个相关的显示来选择所有事件。 如果没有INNER JOIN还有其他方法可以做到,我很想知道如何:)

CREATE TABLE `Event` (
    `Id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `Name` VARCHAR(255) NOT NULL
);
INSERT INTO `Event` (`Name`) VALUES ('My cool event');

CREATE TABLE `Showing` (
    `Id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `EventId` INT UNSIGNED NOT NULL,
    `Place` VARCHAR(50) NOT NULL,

    FOREIGN KEY (`EventId`) REFERENCES `Event`(`Id`),
    UNIQUE (`EventId`, `Place`)
);
INSERT INTO `Showing` (`EventId`, `Place`) VALUES (1, 'School');
INSERT INTO `Showing` (`EventId`, `Place`) VALUES (1, 'Park');



-- Correct queries
SELECT t.* FROM `Event` t INNER JOIN `Showing` t1 ON t.Id=t1.`EventId` WHERE t1.`PlaceId` = 'School';
SELECT t.* FROM `Event` t INNER JOIN `Showing` t1 ON t.Id=t1.`EventId` AND t1.`PlaceId` = 'School';


-- Query leading to duplicate values
SELECT t.* FROM `Event` t INNER JOIN `Showing` t1 ON t.Id=t1.`EventId`;


-- Group by query to prevent duplicate values
SELECT t.* FROM `Event` t INNER JOIN `Showing` t1 ON t.Id=t1.`EventId` GROUP BY t.`Id`;

谢谢!

2 个答案:

答案 0 :(得分:2)

(这应该是评论,但有点长)

  

对于LEFT联接没有问题,但对于一对多关系

,INNER可能会导致重复结果

从这句话可以清楚地看出,至少有一个人对关系数据库的工作方式以及对象关系映射应如何工作非常困惑。

  

查询导致重复值

生成的行不是重复的 - 您编写了查询,因此它不会显示它们的不同之处:

SELECT t1.place, t.* 
FROM Event 
INNER JOIN Showing 
ON Event.Id=Showing.EventId;

如果您对“展示”中的数据不感兴趣,那么为什么它会出现在您的查询中?如果你有没有相关显示记录的事件,那么你应该使用'EXISTS' - 而不是连接(考虑你有一个单一的事件,但300万放映)

SELECT t1.place, t.* 
FROM `Event` t 
WHERE EXISTS (SELECT 1
  FROM Showing
  WHERE Event.Id=Showing.EventId);

如果您正在严格实施ORM,那么您可能根本不应该使用连接编写查询 - 但是恕我直言,使用工厂可以更好地满足这种情况。

答案 1 :(得分:0)

数据显示,“我的酷事”正在公园和学校发生。如果您内部加入表格,您将获得多个结果。

执行此查询以查看正在进行的操作:

Select t.*, t1.* FROM `Event` t INNER JOIN `Showing` t1 ON t.Id=t1.`EventId`;

这是与重复查询相同的查询,但从两个表中选择列。

第一行结果表明该事件正在公园内进行。第二行表示同一事件正在学校发生。