SQL Server选择IN语句不起作用的别名

时间:2013-02-23 20:03:35

标签: sql sql-server select alias

我有以下SELECT声明。

SELECT t.ID, 
       t.SiteID, 
       t.SpareID, 
       t.SpareLocationID, 
       t.Qty, 
       t.IsDefault
  FROM TrainingDB.dbo.LocationsPerSpare t
 WHERE t.SpareID IN
       (SELECT s.SpareID
          FROM TrainingDB.dbo.LocationsPerSpare s
         WHERE s.SpareLocationID = t.SpareLocationID
           AND s.SpareID = t.SpareID
         GROUP BY s.SpareID
        HAVING COUNT(CONVERT(VARCHAR(36), s.SpareID)) > 2)
 ORDER BY t.SpareID

如果我执行该脚本,则返回NULL。但是,如果我删除t.别名,则会正常运行。

SELECT ID, 
       SiteID, 
       SpareID, 
       SpareLocationID, 
       Qty, 
       IsDefault
  FROM TrainingDB.dbo.LocationsPerSpare 
 WHERE SpareID IN
       (SELECT s.SpareID
          FROM TrainingDB.dbo.LocationsPerSpare s
         WHERE s.SpareLocationID = SpareLocationID
           AND s.SpareID = SpareID
         GROUP BY s.SpareID
        HAVING COUNT(CONVERT(VARCHAR(36), s.SpareID)) > 2)
 ORDER BY SpareID

我发现这很奇怪。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

您需要删除

AND s.SpareID = t.SpareID
来自您的子查询的

。当SpareID还没有值时,您正在使用子查询过滤主查询中的SpareID值。

答案 1 :(得分:0)

顺便说一句,您可以使用窗口函数来重写此查询而不使用连接:

select lps.ID, lps.SiteID, lps.SpareID, lps.SpareLocationID, 
       lps.Qty, lps.IsDefault
from (select lps.*,
             count(*) over (partition by spareId) as SpareCnt
      from TrainingDB.dbo.LocationsPerSpare lps
     ) lps
where SpareCnt > 2

您需要别名的原因是因为子查询中的未混淆列在最近的引用处分配给表。所以,

 where s.SpareID = t.SpareID

将外表引用的SpareId与内部引用进行比较。

 where s.SpareID = SpareID

首先确定哪个表SpareID来自哪个。它匹配内部子查询中的列,因此它使用它。表达式相当于:

where s.SpareID = s.SpareId

最后,convert count的用户完全没必要。 Count只计算非NULL值的数量,转换为字符串时不会改变。

例如,当我测试这段代码时,它运行正常:

declare @t uniqueidentifier = newid();

select count(distinct t)
from (select @t as t) v

虽然,有趣的是,这段代码不适用于SQLFiddle。但是有一个错误是@t未定义,这是无关的。