WHERE子句的虚假结果说明

时间:2019-01-08 11:58:08

标签: mysql sql subquery

MySQL 8.由于缺少表名的规范,我在查询中看到一个虚假的行。我知道如何解决它,我想了解它为什么会发生。

请参阅以下小提琴:

http://sqlfiddle.com/#!9/beb1ed/1/0

目的是在计划表中查找计划表中还存在的,与SubscriptionID和日期匹配的任何行。

返回的结果是:

RealWorldVisitDate      CustomerID      SubscriptionID
2019-01-14 00:00:00     5               13  
2019-01-14 00:00:00     17              23  

但是WHERE子句应将结果限制为仅第一行(CustomerID 5 / SubscriptionID 13)。

我知道解决此问题的方法,要解决此问题并返回正确的行,就是按照以下查询在WHERE中指定该表:

SELECT * FROM tblPlanned WHERE ( SELECT COUNT(1) FROM tblScheduled WHERE tblScheduled.SubscriptionID = **tblPlanned.**SubscriptionID AND tblScheduled.DateScheduled = RealWorldVisitDate ) > 0

但是我想了解为什么为什么原始查询(按照小提琴)为CustomerID 17 / SubscriptionID 23返回了一个虚假的行,因为该行带有日期和SubscriptionID的组合不存在在tblScheduled中。显然,这与2个表中重复的SubscriptionID列名称有关,但是我不明白导致它的mysql执行逻辑。

(由于先前对过多细节的投诉,故意缩短了时间。请问我是否需要更多数据等)。

谢谢。


根据小提琴编写的架构和数据:

CREATE TABLE `tblScheduled` (
  `ScheduledTargetID` bigint(20) NOT NULL,
  `DateScheduled` datetime NOT NULL,
  `CustomerID` int(10) UNSIGNED NOT NULL,
  `SubscriptionID` int(10) UNSIGNED NOT NULL
);

INSERT INTO `tblScheduled` (`ScheduledTargetID`, `DateScheduled`, `CustomerID`, `SubscriptionID`) VALUES
(25, '2018-11-19 00:00:00', 16, 15),
(24, '2018-11-19 00:00:00', 17, 23),
(27, '2018-11-23 00:00:00', 5, 1),
(26, '2018-11-23 00:00:00', 14, 18),
(23, '2019-01-14 00:00:00', 5, 13);

CREATE TABLE `tblPlanned` (
  `RealWorldVisitDate` datetime DEFAULT NULL,
  `CustomerID` int(10) UNSIGNED DEFAULT NULL,
  `SubscriptionID` int(10) UNSIGNED DEFAULT NULL
);

INSERT INTO `tblPlanned` (`RealWorldVisitDate`, `CustomerID`, `SubscriptionID`) VALUES
('2019-01-15 00:00:00', 5, 4),
('2019-01-14 00:00:00', 5, 13),
('2019-01-28 00:00:00', 5, 27),
('2019-01-14 00:00:00', 17, 23),
('2019-02-11 00:00:00', 17, 23);


SELECT * FROM tblPlanned WHERE ( SELECT COUNT(1) FROM tblScheduled WHERE tblScheduled.SubscriptionID = SubscriptionID AND tblScheduled.DateScheduled = RealWorldVisitDate ) > 0

2 个答案:

答案 0 :(得分:4)

MySQL在子查询中查找列的默认位置是您要查询的表

SELECT COUNT(1) 
FROM tblScheduled
WHERE tblScheduled.SubscriptionID = SubscriptionID AND tblScheduled.DateScheduled = RealWorldVisitDate

实际上与以下内容相同:

SELECT COUNT(1) 
FROM tblScheduled
WHERE tblScheduled.SubscriptionID = tblScheduled.SubscriptionID AND tblScheduled.DateScheduled = RealWorldVisitDate

等效于

SELECT COUNT(1) 
FROM tblScheduled 
WHERE tblScheduled.DateScheduled = RealWorldVisitDate

解释了由于tblScheduled中带有DateScheduled='2019-01-14 00:00:00'的行与tblPlanned中的两行([CustomerID, SubscriptionID] = [5,13]和{ {1}}。

答案 1 :(得分:1)

  

”在计划表中查找计划表中也存在的任何行   桌子”

这正是INNER JOIN的用途:

SELECT * 
FROM tblPlanned 
INNER JOIN tblScheduled 
  ON tblScheduled.SubscriptionID = tblPlanned.SubscriptionID 
  AND tblScheduled.DateScheduled = tblPlanned.RealWorldVisitDate;

这是更清晰,更高效的行匹配方式,这是在这种情况下SQL的标准操作。

您最初的尝试存在缺陷,部分原因是未使用此方法,还因为在子查询中使用哪个SubscriptionID字段含糊不清-默认情况下,它与子查询中的表匹配,因此您只是在以下地方获得结果字段匹配自己。