2016-05-04 24 views
1

私はこのようになりますテーブルがあります。のSQL Server 2014グループ

CREATE TABLE dbo.Mails (
    ID int IDENTITY(1, 1) NOT NULL, 
    Reference nvarchar(20) COLLATE Latin1_General_CI_AS NULL, 
    Email nvarchar(70) NOT NULL, 
    ETS datetime NULL, --Estimated Time of Shipping 
    ATS datetime NULL, --Actual Time of Shipping 
    ReadOn datetime NULL, 
    Unsubscribed datetime NULL, 
    Bounced datetime NULL, 
    BouncedReason nvarchar(30) COLLATE Latin1_General_CI_AS NULL, 
    Active bit DEFAULT 1 NULL 
) 

を私はチャート上の情報を表示する必要がある、と私は日によってグループにする必要があります。私は次のクエリを構築し、特定のキャンペーンのためReadOnフィールドによってグループの詳細にしたい場合は、したがって

Select 
    CAST(readOn as date) [date], 
    COUNT(*) [read] 
FROM Mails m 
WHERE [email protected] 
GROUP BY CAST(readOn as date) 
ORDER BY CAST(readOn as date) ASC 

and I get something like this: 

sDate  read 
NULL  360 
2016-05-05 67 
2016-05-06 123 
2016-05-07 84 
2016-05-08 62 
2016-05-09 89 
2016-05-10 17 
2016-05-11 12 
2016-05-12 8 
2016-05-13 4 
2016-05-14 4 

しかし、私は、同じクエリでは、だけでなくReadOnフィールドを抽出したいと思いますが、他にもETSなどの分野では、ATS、未登録の/ EASIはあり未読&を読み、

をバウンスし、この

sDate  read ETS  ATS  Bounced  Unsub./Read Unsub/Unread 
NULL  360  
2016-05-05 67  830  570  27   7    3 
2016-05-06 123  0  260  4   9    5 
2016-05-07 84  0  0  0   2    2 
2016-05-08 62  0  0  0   2    4 
2016-05-09 89  0  0  0   7    1 
2016-05-10 17  0  0  0   5    6 
2016-05-11 12  0  0  0   8    2 
2016-05-12 8  0  0  0   1    3 
2016-05-13 4  0  0  0   0    2 
2016-05-14 4  0  0  0   0    2 

のような何かを得ます6つの異なるクエリを構築するよりも、

は、少なくとも次のパスを示すことができますか?

おかげ

ジョー

+2

ETSなどのようにSUM(ReadDate = genericdate、1 else 0)の場合、SUM(ETSdate = genericdate、1 else else endの場合)の総計テーブルに結合します –

+0

'dateadd(DAY、 0、datediff(day、0、m.ReadOn)) '?? –

+0

最初に、グループ化として日付を使用し、その日付に該当するフィールドのカウントを取得する場合は、日付を格納するテーブルが必要です。 第2に、基本フィールド(日付)に関係しないバウンスを含めているので、あなたの質問は本当に意味をなさない。たとえば、日付に含まれる「バウンス」されたレコードの数はどのようにして決定されますか?その日に読まれたものなのでしょうか?そうであれば、他のフィールドにもそのロジックを含める必要があります。これは、ETSが読み込み日と一致した場合にのみカウントされることを意味します。 –

答えて

2

あなたは、いくつかの前処理およびPIVOTでそれを行うことができます。この例では、ストアドプロシージャにクエリを格納しているため、テストが含まれています。私はCTEで前処理を行い、メインのクエリをきちんとした状態に保ちます。

まず、テーブルを作成してそれを設定します。

CREATE TABLE dbo.Mails 
(
    ID int IDENTITY(1, 1) NOT NULL, 
    Reference nvarchar(20) COLLATE Latin1_General_CI_AS NULL, 
    ETS datetime NULL, --Estimated Time of Shipping 
    ATS datetime NULL, --Actual Time of Shipping 
    ReadOn datetime NULL, 
    Unsubscribed datetime NULL, 
    Bounced bit DEFAULT 0 NULL, 
    BouncedReason nvarchar(30) COLLATE Latin1_General_CI_AS NULL, 
    Active bit DEFAULT 1 NULL 
); 
GO 

INSERT INTO dbo.Mails (Reference, ETS, ATS, ReadOn, Unsubscribed, Bounced) 
    VALUES 
     (N'ABC', '2015-05-05', '2015-05-05', '2015-05-05', NULL, 0), 
     (N'ABC', '2015-05-06', '2015-05-07', '2015-05-08', NULL, 0), 
     (N'ABC', '2015-05-05', '2015-05-05', '2015-05-07', NULL, 0), 
     (N'ABC', '2015-05-07', '2015-05-08', '2015-05-09', NULL, 0), 
     (N'ABC', '2015-05-06', '2015-05-07', '2015-05-09', '2015-05-09', 0), 
     (N'ABC', '2015-05-06', '2015-05-07', NULL, '2015-05-08', 0); 

次に、パラメータ@Referenceを使用してストアドプロシージャを作成します。私はCTEを使用して2列の行セットを作成しています。日付とタイプは列として作成します。次に、メインのSELECTステートメントで、結果を与えるためにピボットされています。

CTEによって生成された行セットは、次のようになります。

enter image description here

注:私は要件がその何のためにあるのかは明らかではないだから私は、バウンス列が含まれていません。それは日付の列ではありません。しかし、この例を非常に簡単に拡張できるはずです。

CREATE PROCEDURE dbo.up_ReportMails 
(
    @Reference nvarchar(20) 
) 
AS 
WITH cte AS 
(
    SELECT CAST(ReadOn AS date) AS 'Date', 'R' AS 'Type' 
     FROM dbo.Mails 
     WHERE Reference = @Reference AND ReadOn IS NOT NULL 
    UNION ALL 
    SELECT CAST(ETS AS date), 'E' 
     FROM dbo.Mails 
     WHERE Reference = @Reference AND ETS IS NOT NULL 
    UNION ALL 
    SELECT CAST(ATS AS date), 'A' 
     FROM dbo.Mails 
     WHERE Reference = @Reference AND ATS IS NOT NULL 
    UNION ALL 
    SELECT CAST(Unsubscribed AS date), 'U' 
     FROM dbo.Mails 
     WHERE Reference = @Reference AND UNSUBSCRIBED IS NOT NULL AND ReadOn IS NOT NULL 
    UNION ALL 
    SELECT CAST(Unsubscribed AS date), 'V' 
     FROM dbo.Mails 
     WHERE Reference = @Reference AND UNSUBSCRIBED IS NOT NULL AND ReadOn IS NULL 
) 
SELECT [Date], [R] AS 'Read', [E] AS 'ETS', [A] AS 'ATS', [U] AS 'Unsub/Read', [V] As 'Unsub/Unread' 
    FROM 
     (SELECT [Date], [Type] 
      FROM cte) AS C 
    PIVOT 
    (
     COUNT([Type]) 
     FOR [Type] IN ([R], [E], [A], [U], [V]) 
    ) AS PivotTable 
    ORDER BY [Date]; 

次にテストできます。

EXEC dbo.up_ReportMails @Reference=N'ABC'; 

enter image description here

+0

こんにちはRichardCL、実際に私はピボットに日付を抽出しようとしていましたが、うまくいきませんでした。 あなたのソリューションはうまくいくように見えますが、カレンダーテーブルの問題も解決します。バウンスについて、心配しないでください:私はsprocを修正することができます。実際にはすでに4つのフィールドを追加しています。 – Joe

+0

こんにちは、あなたの時間と忍耐を悪用することはありませんが... Mailsテーブルには "email"フィールドもあり、そのフィールドはDestineeテーブルに参加するために使用できます。上記のデータを国別に抽出しますか? CTE内の各SelectにCountryリファレンスを追加し、Destineeテーブルに参加してcountryIDを 'Type'とともに抽出するか、別の(より良い)アプローチがありますか? – Joe

+0

こんにちは@ジョー私は試して助けてうれしいですが、私はあなたの質問を理解していません。テーブル構造と限られた量のサンプルデータと一緒に、新しい質問として投稿し、これをやったように、あなたがしようとしていることを明確に伝えることができますか? SQL Serverとしてタグ付けすると、私はそれを見ます。 – RichardCL

0

私はこのコードをテストしてみた、それが動作します。 (お持ちでない場合、あなたはそれをGoogleと約10分でものを作ることができます - 彼らは非常にシンプルだし、あなたの時間の負荷を保存します)あなたはカレンダーのテーブルを持っていると仮定すると:

DECLARE @StartDate date = '01/01/2016' 
DECLARE @EndDate date = '05/06/2016' 

SELECT C.BaseDate, 
     ISNULL(SUM(CASE WHEN C.BaseDate = CAST(M.ETS AS DATE) THEN 1 END), 0) AS [ETS], 
     ISNULL(SUM(CASE WHEN C.BaseDate = CAST(M.ATS AS DATE) THEN 1 END), 0) AS [ATS], 
     ISNULL(SUM(CASE WHEN C.BaseDate = CAST(M.ReadOn AS DATE) THEN 1 END), 0) AS [Read On], 
     ISNULL(SUM(CASE WHEN C.BaseDate = CAST(M.Unsubscribed AS DATE) THEN 1 END), 0) AS [Unsubscribed], 
     ISNULL(SUM(CASE WHEN C.BaseDate = CAST(M.Bounced AS DATE) THEN 1 END), 0) AS [Bounced] 
FROM Calendar C 
LEFT OUTER JOIN Mails M 
    ON C.BaseDate = CAST(M.ETS AS DATE) 
    OR C.BaseDate = CAST(M.ATS AS DATE) 
    OR C.BaseDate = CAST(M.ReadOn AS DATE) 
    OR C.BaseDate = CAST(M.Unsubscribed AS DATE) 
    OR C.BaseDate = CAST(M.Bounced AS DATE) 
WHERE C.BaseDate BETWEEN @StartDate AND @EndDate 
GROUP BY C.BaseDate 

基本的にはどのようなあなたの日付範囲のカレンダーテーブルからすべての日付を選択し、日付のANYがその日付と一致する場合はメールテーブルに参加させることです。左結合の目的は、何も起こらない日付が結果セットに返されるようにすることです。それらはすべてゼロになりますが、一貫性のために、またレポートから平均を計算したい場合にはより良い方法です。

datetimeが一致するすべての日付とすべてのレコードを取得したら、日付ごとに一致するETSを持つレコード数、一致するATSを持つレコード数などを計算するだけです。最後に、カレンダーの日付でグループ化すると、すべて完了です。

+1

こんにちは、遅い答えのために申し訳ありませんが、データはありましたが、それほど大きかったわけではないので、私は約2Mのレコードで偽のテーブルを作成しました。CTEのソリューションは平均して14 "を要し、30%以上を要します。したがって、この問題では@ RichardCLソリューションを使用しますが、あなたのアプローチは面白く、将来の問題を覚えています。とにかくあなたの時間と忍耐に感謝します。 Joe – Joe

+0

@Joeフィードバックと情報をありがとう - 間違いなく知っておいてよかった!私はRichardCLの答えをupvoteします。 –