先週、私の同僚の1人が、クエリ出力に欠落している日付を入力するためのクエリの作成を手伝ってくれるように私に依頼しました。私はいくつかの解決策に出くわしましたが、どちらも私には便利ではないようでした。そこで、再帰CTEまたは共通テーブル式を使用して独自にコンパイルしました。
問題の説明
2021年6月1日から10日までのカスタマーケアの着信レコードを含むテーブルがあるとします。一部の日には、コールレコードがありません。 datetime列でGROUPBYステートメントを実行すると、一部の日が欠落します。必要な出力は、欠落している日付は0の値になります。サンプル出力は以下のようになります:
クエリ
SELECT CONVERT(varchar(10),B.call_time,111) AS OriginalDate, COUNT(*) as total
FROM Test1 B
GROUP BY CONVERT(varchar(10),B.call_time,111)
ORDER BY CONVERT(varchar(10),B.call_time,111)
サンプル出力
必要な出力
ソリューションへの私のアプローチ
単純なGROUPBYクエリを使用するのではなく、CTEとSUBQUERYが使用されます。再帰CTEは日付範囲を生成するために使用され、LEFTOUTERJOINは値と日付を組み合わせるために使用されます。ステップバイステップで説明しましょう。
CTE/共通テーブル式
CTEまたは共通テーブル式は、単純なクエリから派生し、単一のSELECT / INSERT / UPDATE / DELETE / MERGE /CREATEVIEWステートメントの実行スコープ内で定義される一時的な名前付き結果セットを指定します。再帰CTEとも呼ばれるそれ自体を参照することもできます。
データの準備
-- Create the table
CREATE TABLE Test1(
call_time datetime,
name varchar(10) default ('Mehedi')
)
GO
-- Populate with sample data
INSERT INTO Test1 (call_time, name)
VALUES ('2021-06-01 08:00','A')
,('2021-06-01 09:05','C')
,('2021-06-01 12:50','E')
,('2021-06-01 16:17','D')
,('2021-06-01 18:53','G')
,('2021-06-03 11:07','F')
,('2021-06-03 13:09','A')
,('2021-06-03 16:26','E')
,('2021-06-03 19:56','C')
,('2021-06-03 21:24','A')
,('2021-06-04 19:13','A')
,('2021-06-04 11:45','B')
,('2021-06-04 15:02','C')
,('2021-06-08 23:02','A')
,('2021-06-09 03:04','E')
クエリを作成する
まず、日付範囲内のすべての日付を生成するCTEを作成します。
DECLARE @StartDate DATE, @EndDate DATE
SET @StartDate = '2021-11-01'
SET @EndDate = '2021-11-08'
;WITH cte AS
( SELECT @StartDate AS sDate
UNION ALL
SELECT DATEADD(DAY,1,sDate)
FROM cte
WHERE sDate < @EndDate
)
SELECT sDate
FROM cte;
これで、このCTEがリファクタリングされ、LEFT OUTER JOINを使用してサブクエリが作成され、値を持たない日付が表示され、値が0になります。
DECLARE @startdate DATETIME = '2021-06-01'
DECLARE @endDate DATETIME = '2021-06-10'
;WITH cte
AS
(
SELECT @startdate as sDate
UNION All
SELECT DATEADD(day,1,sDate) From cte where DATEADD(day,1,sDate) <= @endDate
)
SELECT
C.OriginalDate
,C.total
FROM
(
SELECT CONVERT(varchar(10),A.sDate,111) AS OriginalDate, COUNT(B.call_time) as total
FROM cte A
LEFT OUTER JOIN Test1 B
ON A.sDate = CONVERT(varchar(10),B.call_time,111)
GROUP by CONVERT(varchar(10),A.sDate,111)
) C
ORDER BY C.OriginalDate
最終出力
結論
うまくいけば、それはあなたのために役立つでしょう。ハッピーTSQLing!
私の個人ブログでも利用できます!