1

次の点を考慮してください。

IF OBJECT_ID ('tempdb..#Customer') IS NOT NULL
   DROP TABLE #Customer;

CREATE TABLE #Customer
(
   CustomerKey    INT IDENTITY (1, 1) NOT NULL
  ,CustomerNum    INT NOT NULL
  ,CustomerName   VARCHAR (25) NOT NULL
  ,Planet         VARCHAR (25) NOT NULL
)
GO

INSERT INTO #Customer (CustomerNum, CustomerName, Planet)
VALUES  (1, 'Anakin Skywalker', 'Tatooine')
      , (2, 'Yoda', 'Coruscant')
      , (3, 'Obi-Wan Kenobi', 'Coruscant')
      , (4, 'Luke Skywalker', 'Tatooine')
      , (4, 'Luke Skywalker', 'Tatooine')
      , (4, 'Luke Skywalker', 'Bespin')
      , (4, 'Luke Skywalker', 'Bespin')
      , (4, 'Luke Skywalker', 'Endor')
      , (4, 'Luke Skywalker', 'Tatooine')
      , (4, 'Luke Skywalker', 'Kashyyyk');

合計 10 件のレコードがあることに注意してください。次の 2 つのクエリのいずれかを使用して、CustomerName と PLanet の個別の組み合わせのリストを取得できることを知っています。

SELECT DISTINCT CustomerName, Planet FROM #Customer;

SELECT CustomerName, Planet FROM #Customer
GROUP BY CustomerName, Planet;

ただし、私が望むのは、値自体ではなく、それらの値の数だけを取得する簡単な方法です。すばやく入力できるだけでなく、パフォーマンスも高い方法が必要です。CTE、一時テーブル、テーブル変数、またはサブクエリに値をロードして、レコードをカウントできることはわかっています。これを達成するためのより良い方法はありますか?

4

2 に答える 2

6

これは 2005 年に動作します。

SELECT COUNT(*) AS cnt
FROM
 ( SELECT 1 AS d
   FROM  Customer
   GROUP BY Customername, Planet
 ) AS t ;

SQL-Fiddleでテスト済み。のインデックス(CustomerName, Planet)が使用されます。クエリ プランを参照してください (2012 バージョンの場合):

クエリ プラン

最も単純に考えると、「サブクエリですべての個別の値を取得してからカウントする」と、同じ同一の計画が得られます。

SELECT COUNT(*) AS cnt
FROM
 ( SELECT DISTINCT Customername, Planet
   FROM  Customer
 ) AS t ;

また、ランキング関数を使用したもの(@Aaron Bertrandに感謝)ROW_NUMBER()(2005年バージョンでも効率的かどうかはわかりませんが、テストできます):

SELECT COUNT(*) AS cnt
FROM 
  (SELECT rn = ROW_NUMBER() 
          OVER (PARTITION BY CustomerName, Planet 
                ORDER BY CustomerName) 
   FROM Customer) AS x 
WHERE rn = 1 ;

これを記述する他の方法もありますが(サブクエリがなくても@Mikael Erkssonに感謝します!)、効率的ではありません。

于 2013-06-07T15:23:55.470 に答える
2

サブクエリ/CTE メソッドは、それを行うための「正しい」方法です。

(タイピングに関しては必ずしもパフォーマンスではありませんが)迅速で汚い方法は次のとおりです。

select count(distinct customername+'###'+Planet)
from #Customer;

これ'###'は、偶発的な衝突が発生しないように値を分離することです。

于 2013-06-07T13:26:48.957 に答える