4

これは私にとってトリッキーです...

私はMicrosoftSQLServer 2008で作業しており、個人名を含むテーブルがあります。人の名前は時間の経過とともに変更された可能性があるため、履歴情報もあります。

例:

PID Sequence Name
1   0        Michael Hansen
2   0        Ulla Hansen
2   94       Ulla Margrethe Hansen
2   95       Ulla Margrethe Jensen
3   0        Daniella Oldfield
3   95       Daniella Quist

(私はこのテーブルを作成していません-そのため、データの保存方法を変更することはできません)。PID1の人はマイケルハンセンと呼ばれます。これは彼の現在の名前であり(シーケンス0は常に現在の名前を指定しています)、他のレコードがないため、彼は常にMichaelHansenという名前になっています。

Person PID 2は現在、Ulla Hansen(シーケンス0)と呼ばれています。その前に彼女はUllaMargretheHansenと呼ばれ(これは次のシーケンス番号であるため)、その前に再びUllaMargretheJensenと呼ばれていました。

このテーブルについて私が知っているのは、現在の名前は常にシーケンス0であるということです。また、2つの名前があった場合、次のシーケンスは95です。3つの履歴名:現在の名前:シーケンス0、そのシーケンス94の前と最も古い名前95。

そして、私のデータベースには、最大6つの履歴名(シーケンス0、91、92、93、94、95)に関する情報が含まれています。

今、私は新しいテーブルにすべての名前をリストするように言われました。

PID Name1             Name2                   Name3
1   Michael Hansen
2   Ulla Hansen       Ulla Margrethe Hansen   Ulla Margrethe Jensen
3   Daniella Oldfield Daniella Quist

これまでのところ、ほぼ機能する次のSQLがあります。

SELECT PID 
  ,MAX(CASE sequence WHEN 0 THEN Name ELSE '' END) AS Name1
  ,MAX(CASE sequence WHEN 91 THEN Name ELSE '' END) AS Name2
  ,MAX(CASE sequence WHEN 92 THEN Name ELSE '' END) AS Name3
  ,MAX(CASE sequence WHEN 93 THEN Name ELSE '' END) AS Name4
  ,MAX(CASE sequence WHEN 94 THEN Name ELSE '' END) AS Name5
  ,MAX(CASE sequence WHEN 95 THEN Name ELSE '' END) AS Name6
FROM tblShipTypeHistory
GROUP BY PID

PIDごとに1行で必要なすべての名前が表示されます。また、現在の名前も常にName1の下に表示されます。問題は、2番目に新しい名前をName2列などに含める必要があることです。私の場合は(もちろん)、人が6つの名前を持っている場合にのみ機能します。

したがって、私が行う必要があるのは、PIDが実際に持っている名前の数に基づいて、列Name2からName6に動的に名前を付けることです。そこで、(DECLARE @SQL AS NVARCHAR(MAX)のように動的にSQLを構築してから、@ SQL =を上記のSQLの例に設定してみました)。それから私は次のようなことを試みました

SET @SQL = 'SELECT ....
,MAX(CASE sequence WHEN 91 THEN Name ELSE '' END) AS Name' + COUNT(PID) - 4 + '
,MAX(CASE sequence WHEN 92 THEN Name ELSE '' END) AS Name' + COUNT(PID) - 3 + '
,MAX(CASE sequence WHEN 93 THEN Name ELSE '' END) AS Name' + COUNT(PID) - 2 + '
,MAX(CASE sequence WHEN 94 THEN Name ELSE '' END) AS Name' + COUNT(PID) - 1 + '
,MAX(CASE sequence WHEN 95 THEN Name ELSE '' END) AS Name' + COUNT(PID) + '

論理的にはこれは機能しますが(正しい列名が付けられます)、残念ながら構文「+ count(PID)」は機能しません。

(ふぅ!)それで、これに対する解決策を持っている人はいますか?

前もって感謝します。

4

4 に答える 4

3

RANK()とPIVOT()を組み合わせて実行します。Rank()を使用して名前の「年齢」を把握し、ピボットしてすべての列を取得します。

create table t(pid int not null, sequence int not null, name nvarchar(50))


INSERT INTO t VALUES
(1,   0,        N'Michael Hansen'),
(2,   0,        N'Ulla Hansen'),
(2,   94,       N'Ulla Margrethe Hansen'),
(2,   95,       N'Ulla Margrethe Jensen'),
(3,   0,        N'Daniella Oldfield'),
(3,   95,       N'Daniella Quist')

SELECT pid, [1] as Name1, [2] as Name2, [3] as Name3, [4] as Name4, [5] as Name5, [6] as Name6
FROM
(
SELECT pid, name, rank() over(partition BY pid ORDER BY sequence) AS name_age
FROM t) SOURCE
PIVOT
(
  max(name)
 FOR [name_age] in ([1], [2], [3], [4], [5], [6])) as pvt

SQLフィドル:http ://sqlfiddle.com/#!3 / d8301 / 16

于 2012-08-10T09:40:45.993 に答える
2

COUNT(*)構文エラーは、int を NVARCHAR と連結しようとしていることにあります。私はこのようなものがあなたのために働くと思います:

SET @SQL = 'SELECT ....
,MAX(CASE sequence WHEN 91 THEN Name ELSE '' END) AS Name' + CAST(COUNT(PID) - 4 AS NVARCHAR) + '
,MAX(CASE sequence WHEN 92 THEN Name ELSE '' END) AS Name' + CAST(COUNT(PID) - 3 AS NVARCHAR) + '
,MAX(CASE sequence WHEN 93 THEN Name ELSE '' END) AS Name' + CAST(COUNT(PID) - 2 AS NVARCHAR) + '
,MAX(CASE sequence WHEN 94 THEN Name ELSE '' END) AS Name' + CAST(COUNT(PID) - 1 AS NVARCHAR) + '
,MAX(CASE sequence WHEN 95 THEN Name ELSE '' END) AS Name' + CAST(COUNT(PID) AS NVARCHAR) + '

ただし、まだ手動で SQL を作成しているため、これはあまり将来性がないように思えます。シーケンスが 0 から 91 になる理由はわかりませんが、ギャップがあっても常に昇順であると想定していますそのため、ROW_NUMBER()関数を使用して各名前のインスタンスを取得しました。

DECLARE @SQL NVARCHAR(MAX) = '',
        @PVT NVARCHAR(MAX) = ''

SELECT  @SQL = @SQL + ', COALESCE(' + QUOTENAME('Name' + RowNum) + ', '''') AS ' +  QUOTENAME('Name' + RowNum),
        @PVT = @PVT + ', ' + QUOTENAME('Name' + RowNum)
FROM    (   SELECT  DISTINCT CONVERT(VARCHAR, ROW_NUMBER() OVER(PARTITION BY PID ORDER BY Sequence)) [RowNum]
            FROM    tblShipTypeHistory
        ) rn

SET @SQL = 'SELECT PID' + @SQL + '
            FROM    (   SELECT  PID, 
                                Name, 
                                ''Name'' + CONVERT(VARCHAR, ROW_NUMBER() OVER(PARTITION BY PID ORDER BY Sequence)) [NameID]
                        FROM    tblShipTypeHistory
                    ) data
                    PIVOT
                    (   MAX(Name)
                        FOR NameID IN (' + STUFF(@PVT, 1, 2, '') + ')
                    ) pvt'

EXECUTE SP_EXECUTESQL @SQL

SQL Fiddle の例

于 2012-08-10T09:24:16.843 に答える
1
with names(pid, name, rn) as 
(
  select pid, 
         name, 
         ROW_NUMBER() over (partition by pid order by sequence) 
  from tblShipTypeHistory
)
select pid, 
       [1] as Name1, 
       [2] as Name2, 
       [3] as Name3, 
       [4] as Name4, 
       [5] as Name5, 
       [6] as Name6
from names pivot(max(name) for rn in ([1], [2], [3], [4], [5], [6])) as a;
于 2012-08-10T09:48:02.363 に答える
0

DynamicPIVOTをお試しください http://beyondrelational.com/modules/2/blogs/70/posts/10840/dynamic-pivot-in-sql-server-2005.aspx

于 2012-08-10T09:12:10.347 に答える