2017-02-02 3 views
0

私は検索しましたが、私がここでやろうとしているように具体的なものは見つかりませんでした。私は情報が必要な2つのテーブルがあります。これは、サンプル・スキーマである - 私が働いているからと類似:私はクエリを記述しようとしてるSQL - 列を行に転じる

create table Nodes(
    Caption varchar(max), 
    IP_Address varchar(max), 
    NodeID varchar(max) 
); 

insert into Nodes (Caption, IP_Address, NodeID) 
values ('dev-srvr', '10.0.0.1', '29023'); 
insert into Nodes (Caption, IP_Address, NodeID) 
values ('prod-srvr', '10.0.2.1', '29056'); 
insert into Nodes (Caption, IP_Address, NodeID) 
values ('test-srvr', '10.1.1.1', '29087'); 

create table Volumes(
    Caption varchar(max), 
    NodeID varchar(max) 
); 

insert into Volumes (NodeID, Caption) 
values ('29023', '/'); 
insert into Volumes (NodeID, Caption) 
values ('29023', '/boot'); 
insert into Volumes (NodeID, Caption) 
values ('29023', '/dev/shm'); 
insert into Volumes (NodeID, Caption) 
values ('29023', '/home'); 
insert into Volumes (NodeID, Caption) 
values ('29056', '/'); 
insert into Volumes (NodeID, Caption) 
values ('29056', '/var'); 
insert into Volumes (NodeID, Caption) 
values ('29056', '/opt'); 
insert into Volumes (NodeID, Caption) 
values ('29087', '/tmp'); 

返すよう(where句で...最終版に複数のフィルタを持つことになります) Node.Caption、IP_Address、および関連付けられたすべてのVolumes.Caption(NodeIDに基づいて)。各NodeIDのVolumes.Captionのエントリ数は動的で、1から約60程度です。私が書く方法を知っているすべてはこれです:

select Nodes.Caption, Nodes.IP_Address, Volumes.Caption as Volume 
from Nodes with (nolock) 
inner join Volumes 
on Nodes.NodeID=Volumes.NodeID 
where IP_Address like '10.0%' 

以下を返す:

Caption | IP_Address | Volume 
--------------------------------- 
dev-srvr | 10.0.0.1 |/
dev-srvr | 10.0.0.1 | /boot 
dev-srvr | 10.0.0.1 | /dev/shm 
dev-srvr | 10.0.0.1 | /home 
prod-srvr | 10.0.0.1 | /var 
prod-srvr | 10.0.0.1 | /opt 

しかし、私は必要可能であればNode.Caption、IP_Addressはと一致するすべてのボリュームを示すのNodeIDごとに単一の行であります。この(最終列名は重要ではありません...何もすることができます)のように:

Caption | IP_Address | Volume1 | Volume2 | Volume3 | Volume 4 
---------------------------------------------------------------- 
dev-srvr | 10.0.0.1 |/  | /boot | /dev/shm | /home 
prod-srvr | 10.0.0.1 | /var | /opt 
+0

http://stackoverflow.com/questions/13372276/simple-way-to-transpose-columns-and-rows-in-sql – McNets

+2

可能な重複[Sqlの列と行を移す簡単な方法?](http://stackoverflow.com/questions/13372276/simple-way-to-transpose-columns-and-rows-in-sql) –

答えて

1

SOので、私はよくないである、あなたがこれを行うことがやり方を見せたかったの100のピボット例がありますピボットとして、あなたのインスタンスのために動作します。データセット全体に適合しない場合があり、サンプルデータのみに基づいています。

あなたのテストデータは、自分が行った結果を提供するものではありません。たぶんインサートのタイプミスです。

create table #Nodes(
    Caption varchar(max), 
    IP_Address varchar(max), 
    NodeID varchar(max) 
); 

insert into #Nodes (Caption, IP_Address, NodeID) 
values 
('dev-srvr', '10.0.0.1', '29023'), 
('prod-srvr', '10.0.2.1', '29056'), 
('test-srvr', '10.1.1.1', '29087'); 

create table #Volumes(
    Caption varchar(max), 
    NodeID varchar(max) 
); 

insert into #Volumes (NodeID, Caption) 
values 
('29023', '/'), 
('29023', '/boot'), 
('29023', '/dev/shm'), 
('29023', '/home'), 
('29056', '/'), 
('29056', '/var'), 
('29056', '/opt'), 
('29087', '/tmp'); 


select 
    n.Caption, 
    n.IP_Address, 
    v.Caption as Volume 
from #Nodes n 
inner join #Volumes v 
on n.NodeID=v.NodeID 
where IP_Address like '10.0%' 

;with cte as(
select 
    n.Caption, 
    n.IP_Address, 
    v.Caption as Volume, 
    ROW_NUMBER() over (partition by n.caption, IP_Address order by n.caption) as RN 
from #Nodes n 
inner join #Volumes v 
on n.NodeID=v.NodeID 
where IP_Address like '10.0%') 

select 
    x.caption, 
    x.IP_Address, 
    max(Volume1) as Volume1, 
    max(Volume2) as Volume2, 
    max(Volume3) as Volume3, 
    max(Volume4) as Volume4 
from(
    select 
     Caption, 
     IP_Address, 
     case when RN = 1 then Volume end as Volume1, 
     case when RN = 2 then Volume end as Volume2, 
     case when RN = 3 then Volume end as Volume3, 
     case when RN = 4 then Volume end as Volume4 
    from cte) x 
group by x.Caption, x.IP_Address 


drop table #Nodes 
drop table #Volumes 

DYNAMIC PIVOTを使用した

create table #Nodes(
    Caption varchar(max), 
    IP_Address varchar(max), 
    NodeID varchar(max) 
); 

insert into #Nodes (Caption, IP_Address, NodeID) 
values 
('dev-srvr', '10.0.0.1', '29023'), 
('prod-srvr', '10.0.2.1', '29056'), 
('test-srvr', '10.1.1.1', '29087'); 

create table #Volumes(
    Caption varchar(max), 
    NodeID varchar(max) 
); 

insert into #Volumes (NodeID, Caption) 
values 
('29023', '/'), 
('29023', '/boot'), 
('29023', '/dev/shm'), 
('29023', '/home'), 
('29056', '/'), 
('29056', '/var'), 
('29056', '/opt'), 
('29087', '/tmp'); 



DECLARE @DynamicPivotQuery AS NVARCHAR(MAX) 
DECLARE @ColumnName AS NVARCHAR(MAX) 


select 
    n.Caption, 
    n.IP_Address, 
    v.Caption as Volume, 
    'Volume' + cast(ROW_NUMBER() over (partition by n.caption, IP_Address order by n.caption) as varchar(16)) as Cname 
    --ROW_NUMBER() over (partition by n.caption, IP_Address order by n.caption) as RN 
into #staging 
from #Nodes n 
inner join #Volumes v 
on n.NodeID=v.NodeID 
where IP_Address like '10.0%' 




--Get distinct values of the PIVOT Column 
SELECT @ColumnName= ISNULL(@ColumnName + ',','') 
     + QUOTENAME(Cname) 
FROM (SELECT DISTINCT Cname FROM #staging) AS Cname 

--Prepare the PIVOT query using the dynamic 
SET @DynamicPivotQuery = 
    N'SELECT Caption, IP_Address, ' + @ColumnName + ' 
    FROM #staging 
    PIVOT(MAX(Volume) 
      FOR Cname IN (' + @ColumnName + ')) AS PVTTable' 
--Execute the Dynamic Pivot Query 
EXEC sp_executesql @DynamicPivotQuery 



drop table #Nodes 
drop table #Volumes 
drop table #staging 
+0

ええ、ごめんなさい - 私私のものをSOに正しくコピーしていませんでした。どうもありがとうございます!あなたが思いついたのは、まさに私が頭を悩ましていたものです。質問...動的にする方法はありますか?たとえば、サーバーに15、65などの4つのボリュームがあるかどうかはわかりません。 SQLは何とか多くの 'max(Volume#)をVolume#'として追加し、 'RN =#ならVolume#end Volume#'を必要に応じて追加できますか?それとも、私が必要と思う多くのもの(例えば5から100まで)を追加する方が簡単でしょうか? – fishhbot

+0

@fishhbot何列あるかわからないときはいつでも、ピボットを持つ動的SQLを使用する必要があります。この例では、行の値から明示的に使用する場合と比較して列の名前を作成しています。コードの2番目のスニペットは、row_numberでそれを行う方法を示しています。 – scsimon