1

使用しているテーブルが2つあります。それらを「顧客」と「ポイント」と呼びましょう。

ポイントテーブルは次のようになります。

Account Year M01 M02 M03 M04 M05 M06 M07 M08 M09 M10 M11 M12
123     2011  10   0   0   0  10   0  10   0   0   0   0  10
123     2012   0   0   0   0  10   0   0  10  10  10  10  20
123     2013   5   0   0   0   0   0   0   0   0   0   0   0

しかし、これらのポイントは12か月ごとに機能します。現在の顧客のポイントを計算することは十分に簡単ですが、課題はもはや活動していない顧客にとってです。2013年1月に顧客123が非アクティブになったとすると、12年2月から13年1月までの計算のみが必要になります。ここで、もう1つのテーブルCustomersが登場します。単純化して、次のようになります。

Account   End Date
123       20130105

さて、私がやりたいのは、各顧客が持っているポイントの量を計算するクエリを作成することです。(アクティブな顧客の場合は現在12か月、アクティブではなくなった顧客の場合は過去12か月がアクティブでした。)

詳細は次のとおりです。

  • SQLServer2008を実行しています。
  • これらのテーブルはこのように提供されており、変更することはできません。
  • アクティブな顧客とは、終了日が99991231(9999年12月31日)の顧客です。
  • ポイントテーブルは、顧客がアクティブな顧客である年だけ入力されます。別名、誰かが2009年2月にアクティブな顧客になり、2009年のエントリがあります。2009年7月に非アクティブになった場合、ポイントは2009年2月から7月までしか計算されません。顧客ではなかったため、2008年の行はありません。当時。2009年1月と8月から12月に0が表示されます。
  • さらに、レコードは、顧客がその年にポイントを獲得した場合にのみ作成されます。顧客が1年に0ポイントを獲得した場合、その記録はありません。
  • 国境の場合、月の初日に入ると、その月がカウントされます。たとえば、今日が2013年4月1日であるとしましょう。つまり、2013年5月12日から4月までを合計します。

これはかなり複雑な質問です。もっとよく説明できることがあれば教えてください。ありがとうございました!

4

2 に答える 2

4

残念ながら、テーブル構造ではデータのピボットpointsを解除する必要があります。unpivotは、複数の列から行にデータを取得しますデータが行に入ると、結合、データのフィルタリング、および各アカウントのポイントの合計がはるかに簡単になります。データのピボットを解除するコードは次のようになります。

select account,
  cast(cast(year as varchar(4))+'-'+replace(month_col, 'M', '')+'-01' as date) full_date,
  pts
from points
unpivot
(
  pts
  for month_col in ([M01], [M02], [M03], [M04], [M05], [M06], [M07], [M08], [M09], [M10], [M11], [M12])
) unpiv

SQL FiddlewithDemoを参照してください。クエリは次のような結果をもたらします。

| ACCOUNT |  FULL_DATE | PTS |
------------------------------
|     123 | 2011-01-01 |  10 |
|     123 | 2011-02-01 |   0 |
|     123 | 2011-03-01 |   0 |
|     123 | 2011-04-01 |   0 |
|     123 | 2011-05-01 |  10 |

データがこの形式になったら、テーブルを結合しCustomersて各の合計ポイントを取得できるaccountため、コードは次のようになります。

select 
  c.account, sum(pts) TotalPoints
from customers c
inner join 
(
  select account,
      cast(cast(year as varchar(4))+'-'+replace(month_col, 'M', '')+'-01' as date) full_date,
    pts
  from points
  unpivot
  (
    pts
    for month_col in ([M01], [M02], [M03], [M04], [M05], [M06], [M07], [M08], [M09], [M10], [M11], [M12])
  ) unpiv
) p
  on c.account = p.account
where 
(
  c.enddate = '9999-12-31'
  and full_date >= dateadd(year, -1, getdate()) 
  and full_date <= getdate()  
)
or
(
  c.enddate <> '9999-12-31'
  and dateadd(year, -1, [enddate]) <= full_date
  and full_date <= [enddate]
)
group by c.account

SQL FiddlewithDemoを参照してください

于 2013-03-25T19:44:06.647 に答える
2

お粗末なデータ構造。最初に行うことは、ピボットを解除することです。次に、列としてyear-month-pointsを含むテーブルを取得します。

ここから、最新の12か月を選択できます。実際、顧客がいつ去ったかを心配する必要はありません。おそらくそれ以来、顧客はポイントを獲得していないからです。

SQLの例を次に示します。

with points as (
    select 123 as account, 2012 as year,
           10 as m01, 0 as m02, 0 as m03, 0 as m04, 10 as m05, 0 as m06,
           10 as m07, 0 as m08, 0 as m09, 0 as m10, 0 as m11, 10 as m12
   ),
   points_ym as (
    select account, YEAR, mon, cast(right(mon, 2) as int) as monnum, points
    from points
    unpivot (points for mon in (m01, m02, m03, m04, m05, m06, m07, m08, m09, m10, m11, m12)
    ) as unpvt
   )
select account, SUM(points)
from points_ym
where year*12+monnum >= year(getdate())*12+MONTH(getdate()) - 12
group by account
于 2013-03-25T19:00:13.497 に答える