0

私はこれに苦労しています。テーブルに2つのフィールドがあり、1つにはヘッダー名が含まれ、もう1つには結果が含まれています

例えば、

ResultID  TestID   MemberID    HeaderDefinition             ResultDefinition
1         1        1           Minutes Exercised|KJ Burnt   60|900
2         2        1           Height|Weight|BMI            142|94|35
3         1        2           Minutes Exercised|KJ Burnt   70|1000
4         2        3           Height|Weight|BMI            150|60|20

私がやりたいことは、TestID を渡し、ヘッダーでピボットされていることを確認することです

例えば。テスト 1

MemberID     Minutes Exercised    KJ Burnt
1            60                   900
2            70                   1000

例えば。テスト 2

MemberID     Height     Weight    BMI
1            142        94        35
3            150        60        20

すべての標準的なピボットの例と動的データを見てきましたが、同じフィールドを使用しても機能します。ヘッダーを定義するフィールドと結果を定義するフィールドが必要で、それらを上記の例に結合する方法がわかりません。いただければ幸いです。

ところで、データの構造を変更することはできません。

前もって感謝します。

4

2 に答える 2

0

PIVOT は機能しないと思います。これは、列を行に/その逆に切り替えるためのものです。あなたの例では、パイプ文字 (|) で区切られた単一の列内に (可変数の) 列があります。

そのため、最初にいくつかの準備作業を行う必要があります。この準備作業は、使用しているテストの数と、その 1 つの列内にいくつの異なる列を含めることができるかによって異なります。上記の例の 2 つまたは 3 つの列を使用した 2 つのテストのみの場合は、データを抽出するクエリを 1 つまたは 2 つ "ハードコード" することができます。それよりも変数が多い場合は、より複雑な準備作業を行うためにカーソルまたは一時テーブルが必要になるでしょう。

したがって、ハードコーディングされた 2 つのクエリのセットを使用する例を次に示します。変数の代わりにテーブル データを使用するには、いくつかの小さな調整を行う必要があります。

declare @TestID int, @ResultDefinition varchar(100), @MemberID int
set @TestID = 1
set @MemberID = 1

if @TestID = 1 begin

    set @ResultDefinition = '60|900'

    select  @MemberID, 
        LEFT(@ResultDefinition, CHARINDEX('|',  @ResultDefinition)-1) AS [Minutes Exercised],
        SUBSTRING(@ResultDefinition, CHARINDEX('|',  @ResultDefinition)+1, LEN(@ResultDefinition)) AS [KJ Burnt]
    --from  tblResults 
    --where TestID = @TestID

end else begin

    set @ResultDefinition = '142|94|35'

    select  @MemberID, 
        LEFT(@ResultDefinition, CHARINDEX('|',  @ResultDefinition)-1) AS [Height],
        LEFT(SUBSTRING(@ResultDefinition, charindex('|', @ResultDefinition) + 1, LEN(@ResultDefinition) ), charindex('|', SUBSTRING(@ResultDefinition, charindex('|', @ResultDefinition) + 1, LEN(@ResultDefinition) ))-1) as [Weight],
        reverse(left(reverse(@ResultDefinition),  CHARINDEX('|', reverse(@ResultDefinition))-1)) as [BMI]
    --from  tblResults 
    --where TestID = @TestID

end

それよりも複雑な場合は、実際にはそこに行きたくありません。:) テーブル構造を動的に構築し、関連するデータを入力して、コンテンツを選択する必要があります。

たぶん、他の誰かがよりエレガントなソリューションを持っているかもしれません...

于 2012-07-03T09:00:00.357 に答える
0

これは、次のPIVOTような Split 関数も実装する場合に実行できます。

分割機能:

CREATE FUNCTION [dbo].[Split](@String varchar(MAX), @Delimiter char(1))       
returns @temptable TABLE (items varchar(MAX))       
as       
begin      
    declare @idx int       
    declare @slice varchar(8000)       

    select @idx = 1       
        if len(@String)<1 or @String is null  return       

    while @idx!= 0       
    begin       
        set @idx = charindex(@Delimiter,@String)       
        if @idx!=0       
            set @slice = left(@String,@idx - 1)       
        else       
            set @slice = @String       

        if(len(@slice)>0)  
            insert into @temptable(Items) values(@slice)       

        set @String = right(@String,len(@String) - @idx)       
        if len(@String) = 0 break       
    end   
return 
end;

次に、列に変換する値がわかっている場合は、静的ピボットを使用して値をハードコーディングできます。

select *
from
(
  select h.memberid,
    h.cols,
    r.results
  from
  (
    select t1.resultid,
      t1.testid,
      t1.memberid, 
      h.items cols,
      row_number() over(partition by memberid order by memberid) rn
    from table1 t1
    cross apply dbo.split(t1.headerdefinition, '|') h
    where t1.testid = 1
  ) h
  left join
  (
    select t1.resultid,
      t1.testid,
      t1.memberid, 
      r.items results,
      row_number() over(partition by memberid order by memberid) rn
    from table1 t1
    cross apply dbo.split(t1.resultdefinition, '|') r
    where t1.testid = 1
  ) r
    on h.memberid = r.memberid
    and h.rn = r.rn
) x
pivot
(
  max(results)
  for cols in ([Minutes Exercised], [KJ Burnt])
) p

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

PIVOTただし、エントリごとに異なる数の列があるため、動的を使用する必要があると思います。コードは次のようになります。

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @testid int = 2

select @cols = 
      STUFF((SELECT ',' + QUOTENAME(x.cols) 
             from
             (
               select h.items cols,
                row_number() over(partition by memberid order by memberid) rn
               from table1 t1
               cross apply dbo.split(t1.headerdefinition, '|') h
               where t1.testid = @testid
             ) x
             group by cols, rn
             order by rn
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query 
  = 'SELECT memberid, ' + @cols + ' from 
     (
        select h.memberid,
          h.cols,
          r.results
        from
        (
          select t1.resultid,
            t1.testid,
            t1.memberid, 
            h.items cols,
            row_number() over(partition by memberid order by memberid) rn
          from table1 t1
          cross apply dbo.split(t1.headerdefinition, ''|'') h
          where t1.testid = '+ cast(@testid as varchar(10)) +'
        ) h
        left join
        (
          select t1.resultid,
            t1.testid,
            t1.memberid, 
            r.items results,
            row_number() over(partition by memberid order by memberid) rn
          from table1 t1
          cross apply dbo.split(t1.resultdefinition, ''|'') r
          where t1.testid = '+ cast(@testid as varchar(10)) +'
        ) r
          on h.memberid = r.memberid
          and h.rn = r.rn
      ) x
      pivot
      (
        max(results)
        for cols in ('+@cols+')
      ) p'

execute(@query)

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

次に、渡す結果に応じて、次の@testidいずれかになります。

| MEMBERID | MINUTES EXERCISED | KJ BURNT |
-------------------------------------------
|        1 |                60 |      900 |
|        2 |                70 |     1000 |

または

| MEMBERID | HEIGHT | WEIGHT | BMI |
------------------------------------
|        1 |    142 |     94 |  35 |
|        3 |    150 |     60 |  20 |
于 2012-10-16T20:52:53.563 に答える