0

これは、過去 90 日間に受け取ったリードに関するマーケティング部門からのアドホック リクエストに対して行う簡単なクエリです。

SELECT ID
    ,FIRST_NAME
    ,LAST_NAME
    ,ADDRESS_1
    ,ADDRESS_2
    ,CITY
    ,STATE
    ,ZIP
    ,HOME_PHONE
    ,MOBILE_PHONE
    ,EMAIL_ADDRESS
    ,ROW_ADDED_DTM
FROM WEB_LEADS
WHERE ROW_ADDED_DTM BETWEEN @START AND @END

彼らは、EMAIL_ADDRESS が一致する ADDRESS_1 の以前の出現回数を示す派生列を追加するよう求めています。しかし、彼らは異なる日付範囲を望んでいます。

したがって、派生列は次のようになります。

,COUNT_ADDRESS_1_LAST_1_DAYS,
,COUNT_ADDRESS_1_LAST_7_DAYS
,COUNT_ADDRESS_1_LAST_14_DAYS
etc.

これらの派生列は、少数しかなかったときに更新ステートメントを使用して手動で入力しました。上記のクエリは、実際には、より多くの列を持つ非常に大きなクエリのサンプルにすぎません。実際のリクエストは、13 列の 6 つの日付範囲に分かれています。78 個の追加の更新ステートメントを使用するよりも良い方法があるかどうかを尋ねています。

4

1 に答える 1

2

さまざまな選択肢をハードコードするクエリを実際に作成せずに、電子メールアドレスごとにこれらの78のメトリックすべてを含むクエリを作成するのは難しいと思います。ただし、動的SQLを使用してこのようなピボットクエリを生成できます。これにより、キーストロークが節約され、テーブルに列を追加するときに動的に調整されます。

最終的に得たい結果は次のようになります(ただし、もちろん入力したくないでしょう)。

;WITH y AS
(
  SELECT 
    EMAIL_ADDRESS,

/* aggregation portion */

    [ADDRESS_1] = COUNT(DISTINCT [ADDRESS_1]),
    [ADDRESS_2] = COUNT(DISTINCT [ADDRESS_2]),
    ... other columns

/* end agg portion */

    FROM dbo.WEB_LEADS AS wl 
    WHERE ROW_ADDED_DTM >= /* one of 6 past dates */
    GROUP BY wl.EMAIL_ADDRESS
)
SELECT EMAIL_ADDRESS,

/* pivot portion */

  COUNT_ADDRESS_1_LAST_1_DAYS = *count address 1 from 1 day ago*,
  COUNT_ADDRESS_1_LAST_7_DAYS = *count address 1 from 7 days ago*,
  ... other date ranges ...
  COUNT_ADDRESS_2_LAST_1_DAYS = *count address 2 from 1 day ago*,
  COUNT_ADDRESS_2_LAST_7_DAYS = *count address 2 from 7 days ago*,
  ... other date ranges ...
  ... repeat for 11 more columns ...

/* end pivot portion */
FROM y 
GROUP BY EMAIL_ADDRESS
ORDER BY EMAIL_ADDRESS;

これは少し複雑で、すべて1つのスクリプトとして実行する必要がありますが、チャンクに分割して、上記の部分を入力せずにどのように入力するかについてのコメントを散在させます。(そして、やがて@Bluefeetは、はるかに優れたPIVOTの代替手段となるでしょう。)/* */この回答の大部分をManagement Studioにコピーして、コメントをそのままにして実行できるように、散在するコメントを囲みます。

コピーするコード/コメントは次のとおりです。


/ *最初に、ピボット用のラベルの導出と集計の支援の両方に使用できる日付のテーブルを作成しましょう。私はあなたが言及し、4番目に推測した3つの範囲を追加しましたが、うまくいけば、さらに追加する方法が明確です:* /

DECLARE @d DATE = SYSDATETIME();

CREATE TABLE #L(label NVARCHAR(15), d DATE);

INSERT #L(label, d) VALUES
(N'LAST_1_DAYS',  DATEADD(DAY,   -1,  @d)),
(N'LAST_7_DAYS',  DATEADD(DAY,   -8,  @d)),
(N'LAST_14_DAYS', DATEADD(DAY,   -15, @d)),
(N'LAST_MONTH',   DATEADD(MONTH, -1,  @d));

/ *次に、列名ごとに繰り返されるクエリの部分を作成しましょう。まず、集計部分はちょうどの形式ですcol = COUNT(DISTINCT col)。カタログビューに移動して、列名のリスト(、、およびを除く)を動的に導出し、IDそれらEMAIL_ADDRESSROW_ADDED_DTM#tempテーブルに詰めて再利用します。* /

SELECT name INTO #N FROM sys.columns
WHERE [object_id] = OBJECT_ID(N'dbo.WEB_LEADS')
AND name NOT IN (N'ID', N'EMAIL_ADDRESS', N'ROW_ADDED_DTM');

DECLARE @agg NVARCHAR(MAX) = N'', @piv NVARCHAR(MAX) = N'';

SELECT @agg += ',
  ' + QUOTENAME(name) + ' = COUNT(DISTINCT ' 
  + QUOTENAME(name) + ')' FROM #N;

PRINT @agg;

/ *次に、「ピボット」部分を作成します(私は貧乏人のピボット、つまり一連のCASE表現に取り組んでいますが)。列名ごとに、各範囲に対する条件が必要なので、ラベルテーブルに対して列名のリストを相互結合することでこれを実現できます。(そして、この部分を機能させるために、後でクエリでこの正確な手法を再度使用します/* one of past 6 dates */。* /

SELECT @piv += ',
  COUNT_' + n.name + '_' + l.label
  + ' = MAX(CASE WHEN label = N''' + l.label 
  + ''' THEN ' + QUOTENAME(n.name) + ' END)'
FROM #N as n CROSS JOIN #L AS l;

PRINT @piv;

/ *これで、これら2つの部分が必要に応じて入力されたので、残りを埋める動的SQLステートメントを作成できます。* /

DECLARE @sql NVARCHAR(MAX) = N';WITH y AS
(
    SELECT 
      EMAIL_ADDRESS, l.label' + @agg + '
      FROM dbo.WEB_LEADS AS wl 
      CROSS JOIN #L AS l
      WHERE wl.ROW_ADDED_DTM >= l.d
      GROUP BY wl.EMAIL_ADDRESS, l.label
)
SELECT EMAIL_ADDRESS' + @piv + '
FROM y 
GROUP BY EMAIL_ADDRESS
ORDER BY EMAIL_ADDRESS;';

PRINT @sql;

EXEC sp_executesql @sql;
GO
DROP TABLE #N, #L;

/ *繰り返しになりますが、これはかなり複雑なコードであり、おそらく。を使用すると簡単になりPIVOTます。しかし、@ Bluefeetでさえ、PIVOT動的SQLを使用するバージョンを作成すると思います。これは、ここでIMHOをハードコーディングするには多すぎるためです。* /

于 2013-01-27T03:57:53.990 に答える