1

私はテーブルを持っています:

+----+-------+------+
| id | times | year |
+----+-------+------+
|  5 |     2 | 2008 |
|  6 |    76 | 2008 |
|  2 |    43 | 2009 |
|  4 |     5 | 2009 |
|  1 |     3 | 2010 |
|  9 |     6 | 2010 |
|  7 |   444 | 2011 |
|  8 |     3 | 2011 |
|  3 |    65 | 2012 |
+----+-------+------+

timesこのテーブルから、バケットごとにピボットを作成したいと思いますyear

+--------+------+------+------+------+------+
|        | 2008 | 2009 | 2010 | 2011 | 2012 |
+--------+------+------+------+------+------+
| 0      |      |      |      |      |      |
| 1-30   |    1 |    1 |    2 |    1 |      |
| 31-60  |      |    1 |      |      |      |
| 61-90  |    1 |      |      |      |    1 |
| 91-120 |      |      |      |      |      |
| 121+   |      |      |      |    1 |      |
+--------+------+------+------+------+------+

SQLでこの課題に取り組むにはどうすればよいですか? ご指導ありがとうございました。

4

2 に答える 2

7

これには、SQL サーバーPIVOT関数を使用できます。年とバケットのすべての値がわかっている場合は、クエリをハードコーディングできます。

select *
from
(
  select 
    case 
      when times = 0 then '0' 
      when times >= 1 and times <=30 then '1-30'
      when times >= 31 and times <=60 then '31-60'  
      when times >= 61 and times <=90 then '61-90' 
      when times >= 91 and times <=120 then '91-120' 
      else '121+' end bucket,
    year
  from yourtable
) src
pivot
(
  count(year)
  for year in ([2008], [2009], [2010], [2011], [2012])
) piv;

デモで SQL Fiddle を参照してください

関数にアクセスできない場合は、PIVOT次のように集計関数を使用できますCASE

select bucket,
  sum(case when year = 2008 then 1 else 0 end) [2008],
  sum(case when year = 2009 then 1 else 0 end) [2009],
  sum(case when year = 2010 then 1 else 0 end) [2010],
  sum(case when year = 2011 then 1 else 0 end) [2011],
  sum(case when year = 2012 then 1 else 0 end) [2012]
from
(
  select 
    case 
      when times = 0 then '0' 
      when times >= 1 and times <=30 then '1-30' 
      when times >= 31 and times <=60 then '31-60'  
      when times >= 61 and times <=90 then '61-90' 
      when times >= 91 and times <=120 then '91-120' 
      else '121+' end bucket,
    year
  from yourtable
) src
group by bucket

デモで SQL Fiddle を参照してください

すべてのバケットを一覧表示する必要がある場合は、バケットの範囲をテーブルに保存するか、CTEクエリを使用して保存する必要があります。次のように使用できます。

;with buckets(startbucket, endbucket, rnk) as
(
  select 0, 0, 1 
  union all
  select 1, 30, 2
  union all
  select 31, 60, 3
  union all
  select 61, 90, 4
  union all
  select 91, 120, 5
  union all
  select 121, null, 6
)
select 
  case when startbucket = 0 then '0'
    when endbucket is null then cast(startbucket as varchar(50)) + '+'
    else cast(startbucket as varchar(50)) + '-'+cast(endbucket as varchar(50)) end buckets,
  [2008], [2009], [2010], [2011], [2012]
from
(
  select rnk,
    year, 
    startbucket, 
    endbucket
  from buckets b
  left join yourtable t
    on t.times >= b.startbucket and t.times <= coalesce(b.endbucket, 100000)
) src
pivot
(
  count(year)
  for year in ([2008], [2009], [2010], [2011], [2012])
) piv;

デモで SQL Fiddle を参照してください

結果:

| BUCKETS | 2008 | 2009 | 2010 | 2011 | 2012 |
----------------------------------------------
|       0 |    0 |    0 |    0 |    0 |    0 |
|    1-30 |    1 |    1 |    2 |    1 |    0 |
|   31-60 |    0 |    1 |    0 |    0 |    0 |
|   61-90 |    1 |    0 |    0 |    0 |    1 |
|  91-120 |    0 |    0 |    0 |    0 |    0 |
|    121+ |    0 |    0 |    0 |    1 |    0 |

上記は、転置する必要がある既知の値 (年数) がある場合にうまく機能します。不明な番号がある場合は、次のような動的 SQL を実装する必要があります。

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(year) 
                    from yourtable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'with buckets(startbucket, endbucket, rnk) as
              (
                select 0, 0, 1 
                union all
                select 1, 30, 2
                union all
                select 31, 60, 3
                union all
                select 61, 90, 4
                union all
                select 91, 120, 5
                union all
                select 121, null, 6
              )
              select 
                case when startbucket = 0 then ''0''
                  when endbucket is null then cast(startbucket as varchar(50)) + ''+''
                  else cast(startbucket as varchar(50)) + ''-''+cast(endbucket as varchar(50)) end buckets,
                '+@cols+'
              from
              (
                select rnk,
                  year, 
                  startbucket, endbucket
                from buckets b
                left join yourtable t
                  on t.times >= b.startbucket and t.times <= coalesce(b.endbucket, 100000)
              ) src
              pivot
              (
                count(year)
                for year in ('+@cols+')
              ) piv;'

execute(@query)

デモで SQL Fiddle を参照してください

結果は、静的 (ハードコーディングされた) バージョンと動的バージョンの両方で同じになります。

于 2012-12-04T19:47:17.113 に答える
3

くそっ!ブルーフィートは私を打ち負かしました。私の試みは似ていますが、テーブルを使用してバケットを構成します。

CREATE TABLE Bucket
(
    id int,
    minbound int,
    maxbound int
)

INSERT INTO Bucket VALUES(1, 0, 30)
                    ,(2, 31, 60)
                    ,(3, 61, 90)
                    ,(4, 91, 120)
                    ,(5, 121, null)

次に、CTEの各レコードのバケットを次のように計算できます....

;WITH RecordBucket
AS
(
    SELECT
        r.*,
        b.id as bucketid
    FROM
        Record r
        INNER JOIN Bucket b ON r.times BETWEEN b.minbound and ISNULL(b.maxbound, 20000000)
)

...そして、最後のクエリのバケットに外部結合して、順序付けと空のバケットを含めることができるようにします。

select 
    b.id as BucketId, 
    CASE
        WHEN b.maxbound IS NULL THEN CONVERT(VARCHAR(16), b.minbound) + '+'
        ELSE CONVERT(VARCHAR(16), b.minbound) + ' - ' + CONVERT(VARCHAR(16), b.maxbound)
    END as BucketName,
    [2008],[2009],[2010],[2011] 
from 
    Bucket b
    LEFT JOIN
    (
        SELECT
            bucketid,
            times,
            year
        from
            RecordBucket
    ) rb 
    pivot (count(times) for year in ([2008],[2009],[2010],[2011])) 
    as pvt ON b.id = pvt.bucketid
order by
    bucketid
于 2012-12-04T19:57:03.503 に答える