簡體   English   中英

SQL-將列轉置為行

[英]SQL - Transpose a Column to Row

好的,我已經搜索了,但是找不到像我在這里嘗試的那樣具體的東西。 我有兩個不同的表,需要這些信息。 這是一個示例架構-與我正在工作的類似:

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)。 每個節點ID的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

但是我需要的是每個NodeID有一個ROW,顯示Node.Caption,IP_Address和所有匹配的卷(如果可能)。 像這樣(最后一列的名稱並不重要...可以是任何東西):

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

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

使用動態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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM