我很困惑将WHERE子句的部分放在JOIN的ON中不起作用以及为什么
我想我已经在某处读过,最好将条款作为ON条款的一部分
我尝试了以下(琐碎的例子):
在下面我注意到,对于内部联接,它将连接相同名称的列,但这会导致左联接错误。
然后我注意到ON (Employee.sdetails_id=SalaryDetails.sdetails_id and Employee.status<>5)
没有过滤状态为5的任何内容。我认为它等同于ON (Employee.sdetails_id=SalaryDetails.sdetails_id) WHERE Employee.status<>5
,但事实并非如此。
如果我修改Employee表并将其作为主键primary key (id, status)
,那么我会遇到同样的问题
有人可以解释ON如何工作以及为什么在这种情况下状态不会过滤任何东西,即使它是主键的一部分?
mysql> select * from Employee JOIN SalaryDetails;
+----+------+--------+--------+-------------+-------------+-----------------------------------------------------+
| id | name | status | salary | sdetails_id | sdetails_id | details |
+----+------+--------+--------+-------------+-------------+-----------------------------------------------------+
| 1 | John | 0 | 1000 | 1 | 1 | Hired with the contract of a perm |
| 1 | John | 0 | 1000 | 1 | 2 | Hired with perm contract and salary to be increased |
| 2 | Jim | 0 | 1200 | 1 | 1 | Hired with the contract of a perm |
| 2 | Jim | 0 | 1200 | 1 | 2 | Hired with perm contract and salary to be increased |
| 3 | Nick | 5 | 1500 | 2 | 1 | Hired with the contract of a perm |
| 3 | Nick | 5 | 1500 | 2 | 2 | Hired with perm contract and salary to be increased |
+----+------+--------+--------+-------------+-------------+-----------------------------------------------------+
6 rows in set (0.00 sec)
mysql> select * from Employee LEFT JOIN SalaryDetails;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
mysql> select * from Employee LEFT JOIN SalaryDetails ON (Employee.sdetails_id=SalaryDetails.sdetails_id);
+----+------+--------+--------+-------------+-------------+-----------------------------------------------------+
| id | name | status | salary | sdetails_id | sdetails_id | details |
+----+------+--------+--------+-------------+-------------+-----------------------------------------------------+
| 1 | John | 0 | 1000 | 1 | 1 | Hired with the contract of a perm |
| 2 | Jim | 0 | 1200 | 1 | 1 | Hired with the contract of a perm |
| 3 | Nick | 5 | 1500 | 2 | 2 | Hired with perm contract and salary to be increased |
+----+------+--------+--------+-------------+-------------+-----------------------------------------------------+
3 rows in set (0.00 sec)
mysql> select * from Employee LEFT JOIN SalaryDetails ON (Employee.sdetails_id=SalaryDetails.sdetails_id and Employee.status<>5);
+----+------+--------+--------+-------------+-------------+-----------------------------------+
| id | name | status | salary | sdetails_id | sdetails_id | details |
+----+------+--------+--------+-------------+-------------+-----------------------------------+
| 1 | John | 0 | 1000 | 1 | 1 | Hired with the contract of a perm |
| 2 | Jim | 0 | 1200 | 1 | 1 | Hired with the contract of a perm |
| 3 | Nick | 5 | 1500 | 2 | NULL | NULL |
+----+------+--------+--------+-------------+-------------+-----------------------------------+
3 rows in set (0.00 sec)
mysql> select * from Employee LEFT JOIN SalaryDetails ON (Employee.sdetails_id=SalaryDetails.sdetails_id) where Employee.status<>5;
+----+------+--------+--------+-------------+-------------+-----------------------------------+
| id | name | status | salary | sdetails_id | sdetails_id | details |
+----+------+--------+--------+-------------+-------------+-----------------------------------+
| 1 | John | 0 | 1000 | 1 | 1 | Hired with the contract of a perm |
| 2 | Jim | 0 | 1200 | 1 | 1 | Hired with the contract of a perm |
+----+------+--------+--------+-------------+-------------+-----------------------------------+
2 rows in set (0.00 sec)
mysql> show create table Employee;
+----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Employee | CREATE TABLE `Employee` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
`status` int(11) DEFAULT NULL,
`salary` decimal(5,0) DEFAULT NULL,
`sdetails_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 |
+----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> show create table SalaryDetails;
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| SalaryDetails | CREATE TABLE `SalaryDetails` (
`sdetails_id` int(11) NOT NULL DEFAULT '0',
`details` text,
PRIMARY KEY (`sdetails_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select * from Employee;
+----+------+--------+--------+-------------+
| id | name | status | salary | sdetails_id |
+----+------+--------+--------+-------------+
| 1 | John | 0 | 1000 | 1 |
| 2 | Jim | 0 | 1200 | 1 |
| 3 | Nick | 5 | 1500 | 2 |
+----+------+--------+--------+-------------+
3 rows in set (0.00 sec)
mysql> select * from SalaryDetails;
+-------------+-----------------------------------------------------+
| sdetails_id | details |
+-------------+-----------------------------------------------------+
| 1 | Hired with the contract of a perm |
| 2 | Hired with perm contract and salary to be increased |
+-------------+-----------------------------------------------------+
2 rows in set (0.00 sec)
答案 0 :(得分:2)
ON
子句指定决定何时连接一侧的行可以与连接另一侧的行匹配的逻辑。 WHERE
子句指定整个结果集的过滤逻辑。
在使用ON (Employee.sdetails_id=SalaryDetails.sdetails_id and Employee.status<>5)
的示例中,您选择从Employee
开始的所有行,然后仅在找到匹配的SalaryDetail
条目时要求数据库加入,其中ID为相同,状态不是5.正如您在结果集中看到的,Nick没有SalaryDetails
表中的详细信息,因为这些值为null。没有结果,因为如果状态为5,则要求数据库不要加入。这不会阻止它从Employee
表返回连接的“左”部分。
如果您只想包含实际发生加入的行,那么您将使用INNER JOIN
而不是LEFT JOIN
。我建议reading up on the different types of join。
在许多RDBMS中,您实际上可以将所有逻辑放在WHERE
子句中,但如果在编写SQL时在语义上将连接逻辑与行过滤分开,则(主观上)更清晰。您的数据库将在内部完成相同的工作量。
就我个人而言,我会将您的查询编写为INNER JOIN
,ID为ON
,WHERE
子句中的状态字段为过滤器。
答案 1 :(得分:0)
SELECT * FROM T1 LEFT JOIN T2 ON condition
从T1中选择所有内容,如果找到符合条件的内容,则加入
SELECT * FROM T1 INNER JOIN T2 ON condition
从T1中选择所有内容并加入T2,但只有在T2中找到匹配的部分
所以使用INNER JOIN过滤