MySQL连接查询不排除具有相同ID的行,如果一行失败连接条件

时间:2020-04-24 09:28:10

标签: mysql sql join select

表A具有值

+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
+----+

表B具有值

+----+-----------+----------+
| id | parent_id |  status  |
+----+-----------+----------+
|  1 |         1 |  started |
|  2 |         2 |  stopped |
|  3 |         1 |  stopped |
|  4 |         1 |  stopped |
+----+-----------+----------+

关系B为1:N

如何仅从状态为未启动的表A中获取这些ID。

SELECT 
   id 
FROM A 
JOIN B ON A.id=B.parent_id and B.status <> 'started';

当我运行上面的查询时,我得到这个结果

+----+
| id |
+----+
|  1 |
|  2 |
+----+

不是只显示值2,而是也显示1。我写的查询有什么问题?

4 个答案:

答案 0 :(得分:1)

显示未启动状态。

SELECT A.id FROM A JOIN B ON A.id=B.parent_id and B.status != 'started'

输出:

+----+
| id |
+----+
|  2 |
|  1 |
|  1 |
+----+

答案 1 :(得分:0)

在您的查询中,parent_id 2返回,因为它也停止了 您可以尝试对所述

使用not in子查询
SELECT   id 
FROM A 
JOIN B ON A.id=B.parent_id 
WHERE B.parent_id NOT IN  ( 
    select parent_id
    from B
    B.status = 'started'
)

答案 2 :(得分:0)

我会使用/* * calls: * * File {Close, Read, Write, Size, Sync} * {Path Name Open, Allocate, Free} File * * These are NOT JUST RENAMINGS OF THE UNIX ROUTINES. * Use them for all file activity... * * File fd; * fd = PathNameOpenFile("foo", O_RDONLY); * * AllocateFile(); * FreeFile(); * * Use AllocateFile, not fopen, if you need a stdio file (FILE*); then * use FreeFile, not fclose, to close it. AVOID using stdio for files * that you intend to hold open for any length of time, since there is * no way for them to share kernel file descriptors with other files. * * Likewise, use AllocateDir/FreeDir, not opendir/closedir, to allocate * open directories (DIR*), and OpenTransientFile/CloseTransientFile for an * unbuffered file descriptor. * * If you really can't use any of the above, at least call AcquireExternalFD * or ReserveExternalFD to report any file descriptors that are held for any * length of time. Failure to do so risks unnecessary EMFILE errors. */

not exists

这将从select a.id from a where not exists (select 1 from b where b.parent_id = a.id and b.status = 'started') 中筛选出行,其中a中的任何子记录的状态已开始。

答案 3 :(得分:0)

查询的“未开始”部分将表B过滤到以下内容:

+----+-----------+----------+
| id | parent_id |  status  |
+----+-----------+----------+
|  2 |         2 |  stopped |
|  3 |         1 |  stopped |
|  4 |         1 |  stopped |
+----+-----------+----------+

然后,您的联接正在查找表A中的ID与表B的父ID匹配的行-它将正确返回(但不会两次计数1)

如果您希望上半年返回:

+----+-----------+----------+
| id | parent_id |  status  |
+----+-----------+----------+
|  2 |         2 |  stopped |
+----+-----------+----------+

 PLUS the rows from table A not referred to in table B....

那么上述GMB的答案是正确的-

select a.id
from a
where not exists (select 1 from b where b.parent_id = a.id and b.status = 'started')

这是一个小提琴。 https://sqltest.net/#1005425

但是,按照建议,您可能会在表B中产生许多不必要的重复-许多行说开始和停止,不一定按时间顺序排列(例如-A.id = 1的第一条记录建议这样做)启动后,第3条和第4条记录(大概在此后输入)将其停止,但是您将排除此记录以被启动。

为什么不更改表结构以更新一行?