具有唯一结果行的MYSQL JOIN

时间:2011-04-19 08:01:28

标签: mysql sql join

假设我有2个表,一个叫做类别,一个叫做cat_pages。

类别表包含列ID,标题和时间戳。例如:

CREATE TABLE categories (
    id INT UNSIGNED PRIMARY KEY,
    title VARCHAR(32),
    `timestamp` TIMESTAMP,
    INDEX (title)
) Engine=InnoDB;

cat_pages有2列,cat_id和page_id:

CREATE TABLE cat_pages (
    cat_id INT UNSIGNED 
        REFERENCES categories (id) 
        ON DELETE CASCADE ON UPDATE CASCADE,
    page_id INT UNSIGNED
        REFERENCES pages (id) 
        ON DELETE CASCADE ON UPDATE CASCADE,
    UNIQUE INDEX (cat_id, page_id),
    INDEX (page_id, cat_id),
) Engine=InnoDB;

我正在尝试使用ID上的cat_pages表加入类别表,例如

  1. 仅检索category_pages表中包含id的类别
  2. 每个类别仅在结果集中显示一次
  3. 查询:

    SELECT * FROM categories as c
        LEFT JOIN cat_pages as p ON c.id = p.cat_id
    

    生成一个重复多次类别的结果集(因为cat_pages表中有多个匹配项。我需要什么,以便每个类别只显示一次,如果cat_pages中没有匹配项则根本不显示表

2 个答案:

答案 0 :(得分:11)

如果您不希望类别不在cat_pages中,请不要使用左连接;使用内部联接。左连接包括左表中的每一行,即使右表中没有匹配的行(缺少的字段被赋予NULL值)。右连接类似,但包括右表中的所有行。外连接包括左表和右表中的所有行,连接具有匹配的行并连接没有匹配NULL的行。相反,内部联接仅包括匹配的行。换句话说,左右连接的交点是内连接;他们的联盟是一个外部联盟。 Jeff Atwood发布了一些不错的Venn diagrams describing joins,但应该注意的是,圆圈中的集合不是左右表格的正确,而是左右表格的左右连接的结果。“ / p>

要获得不同的行,您可以使用DISTINCT修饰符:

SELECT DISTINCT c.* 
  FROM categories AS c 
    INNER JOIN cat_pages AS cp ON c.id = cp.cat_id

至于SELECT * ...,请参阅“What is the reason not to use select *?

获取不同行的另一种方法是使用EXISTS子句或IN运算符,但是连接可能性能更高(尽管只有EXPLAIN会告诉您确定) 。只需确保设置了适当的索引。

答案 1 :(得分:-2)

为什么不使用内连接?

SELECT * FROM categories as c INNER JOIN cat_pages as p ON c.id = p.cat_id

或者

SELECT * FROM categories as c LEFT JOIN cat_pages as p ON c.id = p.cat_id WHERE p.cat_id IS NOT NULL

左连接选择左表中的all和右表中的匹配。