SQL - 查询连接结果为空,即使其中一个表中有数据
我有两个表,名为tNetworkSocket
和tPatchpanelPorts
,我用它来过滤数据。
我有数据,当我执行SELECT * FROM tPatchpanelPorts
但是,当SELECT * FROM tNetworkSocket
没有数据。这是对的。
如果我执行SQL - 查询连接结果为空,即使其中一个表中有数据
SELECT Distinct HostID, HostName, HostTypeID, DomainName
FROM tHosts, tDomains, tPatchpanelPorts, tNetworkSocketPort
WHERE tHosts.DomainID=tDomains.DomainID
AND (tPatchpanelPorts.ConnectedHostID = tHosts.HostID OR tNetworkSocketPort.ConnectedHostID = tHosts.HostID) And AccountID=1
我没有得到任何数据,但如果我从查询中删除tNetworkSocketPort
它看起来像:
SELECT Distinct HostID, HostName, HostTypeID, DomainName
FROM tHosts, tDomains, tPatchpanelPorts
WHERE tHosts.DomainID=tDomains.DomainID
AND (tPatchpanelPorts.ConnectedHostID = tHosts.HostID) And AccountID=1
我得到的数据。
我缺少什么
重写查询使用显式JOIN语法和表我已经使用LEFT JOIN,这可能会帮助你
SELECT Distinct HostID, HostName, HostTypeID, DomainName
FROM tHosts
INNER JOIN tDomains ON tHosts.DomainID=tDomains.DomainID
INNER JOIN tPatchpanelPorts ON tPatchpanelPorts.ConnectedHostID = tHosts.HostID
LEFT JOIN tNetworkSocketPort ON tNetworkSocketPort.ConnectedHostID = tHosts.HostID
WHERE AccountID=1
我将tPatchpanelPorts作为LEFT JOIN,因为在第一个查询中,这个或者tNetworkSocketPort必须与HostID匹配。因此,即使它们在tNetworkSocketPort中执行,您也会排除tPatchpanelPorts中没有匹配的HostID的记录。也许OP可以澄清 – kbball
您可以完全删除tNetworkSocketPort上的连接,因为它对查询没有任何影响。在tPatchpanelPorts上使用内部连接,然后应用'DISTINCT'是模拟'IN'或'EXISTS'子句的一种笨拙方式,但对外部连接执行相同操作则什么都不做(除了给DBMS不必要的工作外) 。尽管已经接受了这个答案,但我发现查询不会执行OP希望它执行的操作,因为tNetworkSocketPort处于原始查询中,但并不是真正在这个查询中。 –
@ThorstenKettner很好,谢谢你这么好的解释,我很感谢你的努力,但可能是OP得到了他想找的东西,这就是为什么op认为这是答案。 –
与一些尝试像这样加入:
SELECT Distinct HostID, HostName, HostTypeID, DomainName
FROM tHosts
INNER JOIN tDomains
ON tHosts.DomainID=tDomains.DomainID
LEFT JOIN tPatchpanelPorts
ON tPatchpanelPorts.ConnectedHostID = tHosts.HostID
LEFT JOIN tNetworkSocketPort
ON tNetworkSocketPort.ConnectedHostID = tHosts.HostID
WHERE AccountID=1
您使用的过时的逗号分隔连接非常难以阅读。您的查询转换为:
SELECT Distinct HostID, HostName, HostTypeID, DomainName
FROM tPatchpanelPorts pp
CROSS JOIN tNetworkSocketPort nsp
JOIN tHosts h ON h.HostID IN (pp.ConnectedHostID, nsp.ConnectedHostID)
JOIN tDomains d on d.DomainID = h.DomainID
WHERE AccountID = 1;
您交叉连接tPatchpanelPorts和tNetworkSocketPort以获取所有可能的组合。由于其中一个表为空,因此可能有零个组合。然后你将其他表连接到这个空的结果集,当然它仍然是空的。
此外DISTINCT
通常是写得不好的查询的标志。实际上,当你只需要来自其中两个的数据时,你将加入四张表。其他表属于WHERE
条款。
我想,你希望这样的:(我假设的AccountID驻留在任何tHosts或tDomains你应该用一个限定词来说明这一点。)
SELECT h.HostID, h.HostName, h.HostTypeID, d.DomainName
FROM tHosts h
JOIN tDomains d ON d.DomainID = h.DomainID
WHERE AccountID = 1
AND
(
h.HostID IN (SELECT ConnectedHostID FROM tPatchpanelPorts)
OR
h.HostID IN (SELECT ConnectedHostID FROM tNetworkSocketPort)
);
如果你这样做了'INNER JOIN '对没有数据的表格,它将有效地过滤掉所有的结果。 – Siyual
切换到现代,明确的JOIN语法。易于编写(没有错误),更易于阅读,并且更容易转换为外部联接(如果需要)。 – jarlh
顺便说一句,您使用的是MySQL还是MS SQL Server? (不要标记不涉及的产品。) – jarlh