假设我想选择保持列的组最大值的行,如本文http://dev.mysql.com/doc/refman/5.7/en/example-maximum-column-group-row.html中所述。它确实解决了这个问题。但是我不明白最后的解决方案是如何工作的。如果我执行所描述的所有步骤,我会得到所需的结果:
CREATE TABLE shop (
article INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
dealer CHAR(20) DEFAULT '' NOT NULL,
price DOUBLE(16,2) DEFAULT '0.00' NOT NULL,
PRIMARY KEY(article, dealer));
INSERT INTO shop VALUES
(1,'A',3.45),(1,'B',3.99),(2,'A',10.99),(3,'B',1.45),
(3,'C',1.69),(3,'D',1.25),(4,'D',19.95);
SELECT s1.*
FROM shop s1
LEFT JOIN shop s2 ON s1.article = s2.article AND s1.price < s2.price
WHERE s2.price IS NULL;
+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
| 0001 | A | 3.45 |
| 0001 | B | 3.99 |
| 0002 | A | 10.99 |
| 0003 | B | 1.45 |
| 0003 | C | 1.69 |
| 0003 | D | 1.25 |
| 0004 | D | 19.95 |
+---------+--------+-------+
但我不明白如何使用LEFT JOIN
和复合连接条件获得这个结果。如果我在没有WHERE
子句的情况下尝试相同的查询,我会得到:
SELECT *
FROM shop s1
LEFT JOIN shop s2 ON s1.article = s2.article AND s1.price < s2.price;
+---------+--------+-------+---------+--------+-------+
| article | dealer | price | article | dealer | price |
+---------+--------+-------+---------+--------+-------+
| 0001 | A | 3.45 | 0001 | B | 3.99 |
| 0001 | B | 3.99 | NULL | NULL | NULL |
| 0002 | A | 10.99 | NULL | NULL | NULL |
| 0003 | B | 1.45 | 0003 | C | 1.69 |
| 0003 | C | 1.69 | NULL | NULL | NULL |
| 0003 | D | 1.25 | 0003 | B | 1.45 |
| 0003 | D | 1.25 | 0003 | C | 1.69 |
| 0004 | D | 19.95 | NULL | NULL | NULL |
+---------+--------+-------+---------+--------+-------+
显然,第一个查询只占用了NULL
s的行,这些行恰好包含了所需的值。不太清楚的是,不满足连接条件的某些行如何包含在结果集中并且其中包含NULL
s,而根本不包含其他行。
如果我删除s1.price < s2.price
条件,结果将如下所示:
SELECT *
FROM shop s1
LEFT JOIN shop s2 ON s1.article = s2.article;
+---------+--------+-------+---------+--------+-------+
| article | dealer | price | article | dealer | price |
+---------+--------+-------+---------+--------+-------+
| 0001 | A | 3.45 | 0001 | A | 3.45 |
| 0001 | A | 3.45 | 0001 | B | 3.99 |
| 0001 | B | 3.99 | 0001 | A | 3.45 |
| 0001 | B | 3.99 | 0001 | B | 3.99 |
| 0002 | A | 10.99 | 0002 | A | 10.99 |
| 0003 | B | 1.45 | 0003 | B | 1.45 |
| 0003 | B | 1.45 | 0003 | C | 1.69 |
| 0003 | B | 1.45 | 0003 | D | 1.25 |
| 0003 | C | 1.69 | 0003 | B | 1.45 |
| 0003 | C | 1.69 | 0003 | C | 1.69 |
| 0003 | C | 1.69 | 0003 | D | 1.25 |
| 0003 | D | 1.25 | 0003 | B | 1.45 |
| 0003 | D | 1.25 | 0003 | C | 1.69 |
| 0003 | D | 1.25 | 0003 | D | 1.25 |
| 0004 | D | 19.95 | 0004 | D | 19.95 |
+---------+--------+-------+---------+--------+-------+
据我所知,INNER JOIN
以这种方式工作:首先执行交叉连接,然后根据连接条件过滤结果。对于外连接,我不确定。所以我无法理解为什么,例如
| 0001 | A | 3.45 | 0001 | A | 3.45 |
未包含在上一个查询的结果集中(即添加s1.price < s2.price
时)
| 0001 | B | 3.99 | 0001 | A | 3.45 |
将NULL
包含在下半场。那么有人可以解释SQL JOIN
的行为吗?
答案 0 :(得分:1)
通过使用左连接,您始终可以从左表中获取所有行(在您的情况下为s1)。 当ON子句条件匹配来自s1的特定行时,连接结果将包括它与s2匹配的次数 之后条件适用于结果集(如果有的话)
您还应该记住,条件运算符如=,&gt;如果至少有一个参数为NULL
,则总是返回false所以行
| 0001 | A | 3.45 | 0001 | A | 3.45 |
未添加,因为它与您的子句s1.price&lt;不匹配s2.price
以及行
| 0001 | B | 3.99 | 0001 | A | 3.45 |
只有在您不检查s1.price&lt;之类的价格时才会添加。 s2.price,仅使用文章加入。
答案 1 :(得分:0)
如果两个表之间的所有行匹配,则左连接和内连接之间没有区别..这是为了查询而没有s1.price&lt; s2.price
当两个表之间的条件基于不匹配的值时,左连接很有用..那么在相关字段中你有空值。 使用此功能的条件如s1.price&lt; s2.price(当s1.article = s2.article的行匹配时)将s1.price的值设置为null,当它小于s1.article时的所有值然后用于获取最大值
对于你的问题
0001 | A | 3.45 | 0001 | A | 3.45 |
0001 | B | 3.99 | 0001 | A | 3.45 |
^^ s1.price is not < of ^^ s2.price
所以不符合过滤条件
答案 2 :(得分:0)
你必须记住一个JOIN
子句,无论实际术语多么复杂,归结为一个简单的布尔值true(加入记录)或false(不可能加入)。
这意味着你的自我加入:
1/b/3.99 -> 1/a/3.45
会失败,因为3.99
不小于3.45。这在连接的“右侧”没有留下匹配的记录。但是,由于你正在进行LEFT
加入,这正是你得到的:左边的所有记录,右边有任何匹配的记录 - 如果右边没有匹配的记录,你只需获得{{1} “右”表字段的值。