SQL - 查询连接结果为空,即使其中一个表中有数据

问题描述:

我有两个表,名为tNetworkSockettPatchpanelPorts,我用它来过滤数据。
我有数据,当我执行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 

我得到的数据。

我缺少什么

+2

如果你这样做了'INNER JOIN '对没有数据的表格,它将有效地过滤掉所有的结果。 – Siyual

+6

切换到现代,明确的JOIN语法。易于编写(没有错误),更易于阅读,并且更容易转换为外部联接(如果需要)。 – jarlh

+5

顺便说一句,您使用的是MySQL还是MS SQL Server? (不要标记不涉及的产品。) – jarlh

重写查询使用显式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 
+0

我将tPatchpanelPorts作为LEFT JOIN,因为在第一个查询中,这个或者tNetworkSocketPort必须与HostID匹配。因此,即使它们在tNetworkSocketPort中执行,您也会排除tPatchpanelPorts中没有匹配的HostID的记录。也许OP可以澄清 – kbball

+0

您可以完全删除tNetworkSocketPort上的连接,因为它对查询没有任何影响。在tPatchpanelPorts上使用内部连接,然后应用'DISTINCT'是模拟'IN'或'EXISTS'子句的一种笨拙方式,但对外部连接执行相同操作则什么都不做(除了给DBMS不必要的工作外) 。尽管已经接受了这个答案,但我发现查询不会执行OP希望它执行的操作,因为tNetworkSocketPort处于原始查询中,但并不是真正在这个查询中。 –

+0

@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) 
);