1

以下の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

これはかなり奇妙だと思います。何か案は?

4

2 に答える 2

1

削除する必要があります

AND s.SpareID = t.SpareID

サブクエリから。SpareID にまだ値がない場合、サブクエリを使用して、メイン クエリで SpareID の値をフィルター処理しています。

于 2013-02-23T20:17:15.300 に答える
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最後に、 withのユーザーcountはまったく不要です。 CountNULL 以外の値の数を数えているだけで、これは文字列に変換しても変わりません。

たとえば、このコードをテストすると、問題なく動作します。

declare @t uniqueidentifier = newid();

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

ただし、興味深いことに、このコードは SQLFiddle では機能しません。しかし、@t未定義のエラーが発生していますが、これは無関係です。

于 2013-02-23T21:53:30.223 に答える