0

重複の可能性:
SQL Server: 数日間データが存在しない場合でも、日付範囲内のすべての日を選択する方法

この質問の言い方がよくわからなかったのですが、説明してみます。次のようなクエリを使用して、いくつかの基本的なレポートを作成しようとしています。

SELECT COUNT(*) AS count, h_date FROM (SELECT CONVERT(VARCHAR(10), h_time, 102) AS h_date FROM hits h GROUP BY h_date ORDER BY h_date

これは、グラフを作成するために使用する次のような結果を返します。

8 2012.05.06
2 2012.05.07
9 2012.05.09

ご覧のとおり、8 日はヒットがなかったため、欠落しています。結果のない日付の値を取得する方法はあります0か、それとも事後に結果を解析して手動で追加する必要がありますか?

4

2 に答える 2

1

既存のカタログビューを使用して、開始日から終了日までの日付の連続範囲を導き出すことができます。次に、データへの結合をそのままにしておくことができます。欠落している日付は0で表示されます。

DECLARE @min SMALLDATETIME, @max SMALLDATETIME;

SELECT @min = MIN(h_time), @max = MAX(h_time)
  FROM dbo.hits 
  -- WHERE ?

-- or if you just want a fixed range:

-- SELECT @min = '20120101', @max = '20120131';

;WITH n(d) AS 
(
  SELECT TOP (DATEDIFF(DAY, @min, @max)+1) 
   DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY [object_id]) - 1, DATEDIFF(DAY, 0, @min))
  FROM sys.all_objects ORDER BY [object_id]
)
SELECT n.d, [count] = COUNT(h.h_time)
  FROM n
  LEFT OUTER JOIN dbo.hits AS h
  ON h.h_time >= n.d
  AND h.h_time < DATEADD(DAY, 1, n.d)
  -- AND --WHERE clause against hits?
  GROUP BY n.d;
于 2012-09-18T20:34:07.840 に答える
1

私は、システム テーブルを使用してダミー レコードを作成し、結合することはあまり好きではありませんが、これは非常に一般的な方法です。

Aaron Bertrand の回答を参考にして、代わりに共通テーブル式 (CTE) を再帰式に変更しました。クエリを実行するためにテーブルにアクセスする必要がないため、より高速です。とにかく前のバージョンが遅いというわけではありません。

「OPTION (MAXRECURSION 0);」を指定する必要があります。そうしないと、返される行数がデフォルト (100) に制限されます。0 の値は無制限の行を返します。

DECLARE @min SMALLDATETIME, @max SMALLDATETIME;

--SELECT @min = MIN(h_time), @max = MAX(h_time)
--  FROM dbo.hits 

SELECT @min = '20120101', @max = '20121231';


WITH recursedate(each_date, date_index) AS
(
SELECT @min, 0 

UNION ALL 
SELECT DATEADD(DAY,date_index+1,@min), date_index+1
    FROM recursedate
    WHERE DATEADD(DAY,date_index+1,@min) <= @max
)



SELECT recursedate.each_date, [count] = COUNT(h.h_time)
  FROM recursedate
  LEFT OUTER JOIN dbo.hits AS h
  ON --CONVERT(SMALLDATETIME,h.h_time) =  recursedate.dates 
  h.h_time >= recursedate.each_date
   AND h.h_time < DATEADD(DAY, 1, recursedate.each_date)
  -- AND --WHERE clause against hits?
  GROUP BY recursedate.each_date
   OPTION (MAXRECURSION 0); -- The default is 100 so you'll only get 100 dates, 0 is unlimited.
于 2012-09-19T05:11:33.190 に答える