6

私のテーブルは次のようになります:

患者テーブル

PatientId   Name
1           James
...

訪問テーブル

Date    PatientID_FK    Weight
1/1     1               220
2/1     1               210 
...

を返すクエリを作成するにはどうすればよいですか

PatientId    Name    Visit1Date    Visit1Weight    Visit2Date    Visit2Weight    ...
1            James   1/1           220             2/1           210
2            ...

この方法で列を追加するにはどうすればよいですか?それを書く方法はSELECT?助けてください。


StackExchangeに関するいくつかの投稿では、SQLステートメントで処理することは不可能であると述べています。本当にそうですか?

4

1 に答える 1

7

pivotこのタイプのデータ変換は、aと関数の両方で実行する必要がありunpivotます。訪問は不明になるため、動的SQLを使用することをお勧めします。ただし、最初に、プロセスがどのように機能するかを理解しやすくするために、値をハードコーディングしてクエリを作成する方法を示します。

まず、値が同じ列になるようにと列を作成UNPIVOTする必要があります。これは、クエリまたはunpivot関数を使用して実行できます。dateweightUNION ALL

UNPIVOT:

select patientid, name, rn, col, value
from
(
  select p.patientid, p.name, convert(char(5), v.date, 110) date, 
    cast(v.weight as char(5)) weight,
    row_number() over(partition by PatientID_FK order by date) rn
  from patients p
  left join visits v
    on p.patientid = v.PatientID_FK
) src
unpivot
(
  value
  for col in (date, weight)
) unpiv

SQL FiddlewithDemoを参照してください。このクエリの結果は、日付列と重み列の両方の値を複数の行を持つ単一の列に配置します。レコードにaを適用したrow_number()ので、訪問するたびにどのような値になるかがわかります。

| PATIENTID |  NAME | RN |    COL | VALUE |
-------------------------------------------
|         1 | James |  1 |   date | 01-01 |
|         1 | James |  1 | weight | 220   |
|         1 | James |  2 |   date | 02-01 |
|         1 | James |  2 | weight | 210   |

ピボット:

次のステップはPIVOT、列の項目に関数を適用するcolことですが、最初に名前を変更して、必要な名前が付けられるようにする必要があります。

これを行うには、SELECTステートメントを少し変更して、行番号を列名に追加します。

select patientid, name, 'Visit'+col + cast(rn as varchar(10)) new_col, 
  value
from ...

これにより、列として必要な名前である新しい名前が得られます。

Visitdate1 
Visitweight1
Visitdate2
Visitweight2

データに対してPIVOT、値をハードコーディングすると、クエリは次のようになります。

select *
from
(
  select patientid, name, 'Visit'+col + cast(rn as varchar(10)) new_col, 
    value
  from
  (
    select p.patientid, p.name, convert(char(5), v.date, 110) date, 
      cast(v.weight as char(5)) weight,
      row_number() over(partition by PatientID_FK order by date) rn
    from patients p
    left join visits v
      on p.patientid = v.PatientID_FK
  ) src
  unpivot
  (
    value
    for col in (date, weight)
  ) unpiv
) s1
pivot
(
  max(value)
  for new_col in (Visitdate1,Visitweight1,
                  Visitdate2,Visitweight2)
) piv

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

動的ピボット:

これがどのように設定されるかの背後にあるロジックを説明したので、動的SQLを使用してこれと同じプロセスを実装する必要があります。動的SQLバージョンは次のようになります。

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @colsPivot as  NVARCHAR(MAX)

select @colsUnpivot = stuff((select ', '+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('visits') and
               C.name not in ('PatientID_FK')
         for xml path('')), 1, 1, '')

select @colsPivot = STUFF((SELECT  ',' + quotename('Visit'+c.name 
                                          + cast(v.rn as varchar(10)))
                    from
                    (
                       select row_number() over(partition by PatientID_FK order by date) rn
                       from visits
                    ) v
                    cross apply sys.columns as C
                   where C.object_id = object_id('visits') and
                     C.name not in ('PatientID_FK')
                   group by c.name, v.rn
                   order by v.rn
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query 
  = 'select *
      from
      (
        select patientid, name, ''Visit''+col + cast(rn as varchar(10)) new_col,
          value
        from 
        (
          select p.patientid, p.name, convert(char(5), v.date, 110) date, 
            cast(v.weight as char(5)) weight,
            row_number() over(partition by PatientID_FK order by date) rn
          from patients p
          left join visits v
            on p.patientid = v.PatientID_FK
        ) x
        unpivot
        (
          value
          for col in ('+ @colsunpivot +')
        ) u
      ) x1
      pivot
      (
        max(value)
        for new_col in ('+ @colspivot +')
      ) p'

exec(@query)

SQL FiddlewithDemoを参照してください

両方のバージョンの結果は次のとおりです。

| PATIENTID |  NAME | VISITDATE1 | VISITWEIGHT1 | VISITDATE2 | VISITWEIGHT2 |
-----------------------------------------------------------------------------
|         1 | James |      01-01 |        220   |      02-01 |        210   |
于 2013-01-29T19:58:04.957 に答える