假设我有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表加入类别表,例如
查询:
SELECT * FROM categories as c
LEFT JOIN cat_pages as p ON c.id = p.cat_id
生成一个重复多次类别的结果集(因为cat_pages表中有多个匹配项。我需要什么,以便每个类别只显示一次,如果cat_pages中没有匹配项则根本不显示表
答案 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和右表中的匹配。