1

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

Name   Date      Value
-----------------------
Test 1/1/2001   10
Test 2/1/2001   17
Test 3/1/2001   52
Foo  5/4/2011   15
Foo  6/4/2011   321
My   15/5/2005  36
My   25/7/2005  75

そして、私はこのような結果を示したいと思います:

Name   Date      Value  Name   Date      Value  Name   Date      Value
---------------------------------------------------------------------
Test 1/1/2001    10      Foo  5/4/2011   15      My   15/5/2005  36
Test 2/1/2001    17      Foo  6/4/2011   321     My   25/7/2005  75
Test 3/1/2001    52

名前列にある列と同じ数の列を表示する必要があります

SQLでこれを行うにはどうすればよいですか?

4

2 に答える 2

6

必要な結果を得るには、テーブルの列のピボットを解除し、ピボット関数を適用する必要あります。

ピボット解除は、UNPIVOT関数を使用CROSS APPLYするか、で使用できますVALUES

UNPIVOT:

select rn, 
  col +'_'+cast(dr as varchar(10)) col, 
  new_values
from
(
  select name, 
    convert(varchar(10), date, 101) date, 
    cast(value as varchar(10)) value,
    dense_rank() over(order by name) dr,
    row_number() over(partition by name order by date) rn
  from yourtable
) d
unpivot
(
  new_values
  for col in (name, date, value)
) un;

クロスアプライ:

select rn, 
  col +'_'+cast(dr as varchar(10)) col, 
  c.value
from
(
  select name, 
    convert(varchar(10), date, 101) date, 
    cast(value as varchar(10)) value,
    dense_rank() over(order by name) dr,
    row_number() over(partition by name order by date) rn
  from yourtable
) d
cross apply
(
  values
    ('Name', name), ('Date', date), ('Value', Value)
) c (col, value);

両方のバージョンのデモを含むSQLフィドルを参照してください。これにより、次の結果が得られます。

| RN |     COL | NEW_VALUES |
-----------------------------
|  1 |  name_1 |        Foo |
|  1 |  date_1 | 04/05/2011 |
|  1 | value_1 |         15 |
|  2 |  name_1 |        Foo |
|  2 |  date_1 | 04/06/2011 |
|  2 | value_1 |        321 |
|  1 |  name_2 |         My |
|  1 |  date_2 | 05/15/2005 |
|  1 | value_2 |         36 |

これらのクエリは、既存の列の値を取得して行に変換します。それらが行になったら、ウィンドウ関数を使用して新しい列名を作成しますdense_rank

データが行に変換されたら、(値で作成された)新しい列名を使用して関数dense_rankを適用しPIVOTます。

UNPIVOTを使用したPIVOT:

select name_1, date_1, value_1,
  name_2, date_2, value_2,
  name_3, date_3, value_3
from
(
  select rn, 
    col +'_'+cast(dr as varchar(10)) col, 
    new_values
  from
  (
    select name, 
      convert(varchar(10), date, 101) date, 
      cast(value as varchar(10)) value,
      dense_rank() over(order by name) dr,
      row_number() over(partition by name order by date) rn
    from yourtable
  ) d
  unpivot
  (
    new_values
    for col in (name, date, value)
  ) un
) src
pivot
(
  max(new_values)
  for col in (name_1, date_1, value_1,
              name_2, date_2, value_2,
              name_3, date_3, value_3)
) piv;

SQL FiddlewithDemoを参照してください

CROSS APPLYを使用したピボット:

select name_1, date_1, value_1,
  name_2, date_2, value_2,
  name_3, date_3, value_3
from
(
  select rn, 
    col +'_'+cast(dr as varchar(10)) col, 
    c.value
  from
  (
    select name, 
      convert(varchar(10), date, 101) date, 
      cast(value as varchar(10)) value,
      dense_rank() over(order by name) dr,
      row_number() over(partition by name order by date) rn
    from yourtable
  ) d
  cross apply
  (
    values
      ('Name', name), ('Date', date), ('Value', Value)
  ) c (col, value)
) src
pivot
(
  max(value)
  for col in (name_1, date_1, value_1,
              name_2, date_2, value_2,
              name_3, date_3, value_3)
) piv;

SQL FiddlewithDemoを参照してください。

ダイナミックPIVOT:

上記のバージョンは、列の数が限られているか既知の場合にうまく機能します。そうでない場合は、動的SQLを使用する必要があります。

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

select @cols = STUFF((SELECT ',' + QUOTENAME(col +'_'+cast(dr as varchar(10)))
                    from 
                    (
                      select dense_rank() over(order by name) dr
                      from yourtable
                    ) t
                    cross apply
                    (
                      values(1, 'Name'), (2, 'Date'), (3, 'Value')
                    ) c (sort, col)
                    group by col, dr, sort
                    order by dr, sort
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT ' + @cols + ' 
              from 
             (
                select rn, 
                  col +''_''+cast(dr as varchar(10)) col, 
                  c.value
                from
                (
                  select name, 
                    convert(varchar(10), date, 101) date, 
                    cast(value as varchar(10)) value,
                    dense_rank() over(order by name) dr,
                    row_number() over(partition by name order by date) rn
                  from yourtable
                ) d
                cross apply
                (
                  values
                    (''Name'', name), (''Date'', date), (''Value'', Value)
                ) c (col, value)
            ) x
            pivot 
            (
                max(value)
                for col in (' + @cols + ')
            ) p'

execute(@query)

SQL FiddlewithDemoを参照してください。

各クエリの結果は次のとおりです。

| NAME_1 |     DATE_1 | VALUE_1 | NAME_2 |     DATE_2 | VALUE_2 | NAME_3 |     DATE_3 | VALUE_3 |
-------------------------------------------------------------------------------------------------
|    Foo | 04/05/2011 |      15 |     My | 05/15/2005 |      36 |   Test | 01/01/2001 |      10 |
|    Foo | 04/06/2011 |     321 |     My | 07/25/2005 |      75 |   Test | 01/02/2001 |      17 |
| (null) |     (null) |  (null) | (null) |     (null) |  (null) |   Test | 01/03/2001 |      52 |
于 2013-03-21T16:47:47.423 に答える
0

手でまたはプログラムで。ほとんどの人は、出力を直線的に表示することに慣れています(デフォルト)。誰かがあなたにこれをするように頼んでいるなら、あなたは彼らにそれがアプリケーションがどのように機能するかではないことを伝えることができます。結果セットをcsvにエクスポートし、それをExcelなどにインポートして手動で再フォーマットするか、ASP.netやPHPなどのサーバーサイド言語を使用して結果をテーブルにフォーマットできます。

出力を解析しているときに、最後の変数名を現在の変数と照合することができます。それらが異なる場合は、列を追加します。それらはデータベースから順番に出てくる可能性が高いため、スクリプトを作成するのはまだ難しいでしょう。したがって、test、test、test、foo、fooのようなシーケンスがあります。これは、列数を取得するためにデータを編成するために多次元配列を作成する必要があることを意味します。次に、それに基づいて、行名をカウントするカウンターを使用してテーブルをセットアップし、その下にデータを設定します。

使い慣れたアプリがわからないため、PHPでは多次元配列からの出力は次のようになります。

row [1]['name']=test
row [1][test][1]['date'] = 1/1/2001

ただし、これは視覚的な出力です。データベースは、データを保持し、直感的な方法でデータを返すように設計されています。

于 2013-03-21T16:33:05.783 に答える