【问题标题】:Introduce sub query with EXISTS使用 EXISTS 引入子查询
【发布时间】:2016-06-12 07:37:22
【问题描述】:

我有一个很长的查询,当我执行时抛出异常。 查询:

SELECT HostID,HostName,RackID,HostTypeID,DomainName,RackNumberOfHeightUnits,RackStartHeightUnits 
FROM tHosts, tDomains   
WHERE tHosts.DomainID=tDomains.DomainID AND (RackID IN ( SELECT tRacks.Name,tRacks.RackID,tRacks.SiteID,tRacks.Description,NumberOfHeightUnits   
                                                         FROM tDomains, tSites, tRacks   
                                                         WHERE   tDomains.AccountID= tSites.AccountID    
                                                         AND tSites.SiteID = tRacks.SiteID    
                                                         AND tSites.SiteID = 2  
                                                         AND tDomains.AccountID=1 ) 
AND  SiteID IN (SELECT SiteID FROM tSites WHERE SiteID IN (SELECT SiteID FROM tSites WHERE AccountID=1)))AND AccountID=1

这里的查询正在完成:

SELECT tRacks.Name,tRacks.RackID,tRacks.SiteID,tRacks.Description,NumberOfHeightUnits 
                                                         FROM tDomains, tSites, tRacks  
                                                         WHERE tDomains.AccountID= tSites.AccountID  
                                                         AND tSites.SiteID = tRacks.SiteID  
                                                         AND tSites.SiteID = 2  
                                                         AND tDomains.AccountID=1 

**错误:**当不使用EXISTS引入子查询时,选择列表中只能指定一个表达式。
提前谢谢。

【问题讨论】:

  • 将AND (RackID IN ( SELECT tRacks.Name,tRacks.RackID,tRacks.SiteID,tRacks.Description,NumberOfHeightUnits 更改为AND (RackID IN ( SELECT tRacks.RackID
  • 第一个提示:使用明确的join 语法。 @artm 是对的,但看起来您还需要来自 tRacks 的数据,在这种情况下,您应该将 join 它添加到您的外部查询中。此外,这不是一个长查询,实际上很短。

标签: sql sql-server exists


【解决方案1】:

我认为您应该重新查看您的 SQL 并确定您认为需要以现有方式编写查询的确切原因,这不仅是为了您自己在调试时的理智,而且因为您似乎可以简化这一点如果对发生的事情有更多的了解,请多多询问。

从您的 SQL 看来,您似乎想要给定帐户(ID 1)和站点(ID 2)的所有主机、域和机架详细信息

当您在选择中使用逗号分隔的表列表编写查询时,a) 立即更难阅读,并且 b) 以后其他开发人员更有可能来修改您的查询,您的第一个选择将被重写为:

SELECT (columns)
FROM tHosts
INNER JOIN tDomains ON tDomains.DomainID = tHosts.DomainID

然后,您想要加入以查找 ID 为 2 的站点和 ID 为 1 的帐户的机架详细信息。您的 tDomains 和 tSites 具有共同的 AccountID 列,因此您可以加入这些列:

INNER JOIN tSites ON tSites.AccountID = tDomains.AccountID

您的 tRacks 和 tSites 有一个共同的 SiteID 列,因此您可以加入这些列:

INNER JOIN tRacks ON tRacks.SiteID = tSites.SiteID

然后您可以应用 where 子句将结果过滤到您需要的条件:

WHERE tDomains.AccountID = 1
AND tSites.SiteID = 2

您现在有以下查询:

SELECT HostID
     , HostName
     , RackID
     , HostTypeID
     , DomainName
     , RackNumberOfHeightUnits
     , RackStartHeightUnits 
FROM tHosts
INNER JOIN tDomains ON tDomains.DomainID = tHosts.DomainID
INNER JOIN tSites ON tSites.AccountID = tDomains.AccountID
INNER JOIN tRacks ON tRacks.SiteID = tSites.SiteID
WHERE tDomains.AccountID = 1
AND tSites.SiteID = 2

SQL 中的最后一行似乎没有必要,因为您再次为 ID 为 1 的帐户选择站点 ID(并且您已经在内部选择中过滤到这些机架)。

这里可能缺少一些东西,因为如果不查看表定义就很难理解您的确切域,但您似乎可以提高可读性,但更重要的是通过一些更改来提高查询的性能?

【讨论】:

  • 非常感谢您的回复。非常有帮助。 :)
【解决方案2】:

以下子查询

SELECT SiteID FROM tSites WHERE SiteID IN (SELECT SiteID FROM tSites WHERE AccountID=1)

似乎等于

SELECT SiteID FROM tSites WHERE AccountID = 1

你可以用第二个替换第一个希望摆脱错误

【讨论】:

    【解决方案3】:

    对于IN,您必须返回一列,即要与之比较的列:

    改变这个

     ...AND (RackID IN ( SELECT tRacks.Name,tRacks.RackID,tRacks.SiteID,tRacks.Description,NumberOfHeightUnits   
                         FROM tDomains, tSites, tRacks ...
    

    到这里:

    ... AND (RackID IN ( SELECT tRacks.RackID FROM tDomains, tSites, tRacks ...
    

    在这个地方不会使用其他列“外部”

    但是 - 老实说 - 整个查询看起来像 - 嗯 - 可以改进......

    【讨论】:

    • 非常感谢您的回答。
    猜你喜欢
    • 1970-01-01
    • 2010-12-08
    • 2020-12-27
    • 1970-01-01
    • 1970-01-01
    • 2011-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多