mysql - 我们可以将什么条件作为 JOIN 的 ON 的一部分?

标签 mysql sql join left-join

我对何时将部分 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)

最佳答案

ON子句指定决定何时来自连接一侧的行可以与来自连接另一侧的行相匹配的逻辑。 WHERE子句指定整个结果集的过滤逻辑。

在您的示例中使用 ON (Employee.sdetails_id=SalaryDetails.sdetails_id and Employee.status<>5)您正在选择 Employee 中的所有行开始,然后要求数据库仅在找到匹配的 SalaryDetail 时才加入条目,其中 ID 相同,状态不是 5。正如您在结果集中看到的,Nick 没有来自 SalaryDetails 的详细信息。表,因为这些值为空。没有结果,因为您已要求数据库在状态为 5 时不要加入。这不会阻止它从 Employee 返回加入的“左”部分。表。

如果您只想包含实际发生连接的行,那么您可以使用 INNER JOIN而不是 LEFT JOIN .我会推荐reading up on the different types of join .

在许多 RDBMS 中,您实际上可以将所有逻辑放在 WHERE 中子句,但如果在编写 SQL 时从语义上将连接逻辑与行过滤分开,则(主观上)会更清楚。您的数据库将在内部完成相同数量的工作。

我个人会将您的查询写成 INNER JOIN , 与 ON对于 ID,以及 WHERE 中状态字段的过滤器条款。

关于mysql - 我们可以将什么条件作为 JOIN 的 ON 的一部分?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26831652/

相关文章:

MySQL 选取所有30天未登录的用户

sql - 如何在 electron.js 应用程序中保存用户数据?

postgresql - Postgres - 加入更新给出了错误的结果

php - mysql Unix时间戳检查是否已过去2小时

php - 如何优化我的查询?

mysql - 我可以只在 JOIN 失败的地方使用 MySQL SELECT 行吗?

sql - 从自然连接中排除列

mysql - 哈希 MySQL 数据库模式

php - 如何在php mysql中获取father_id中的所有产品

MySQL空间关系查询返回空结果集?