SQL-将列转置为行 [英] SQL - Transpose a Column to Row

查看:93
本文介绍了SQL-将列转置为行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,我已经搜索了,但是找不到像我在这里尝试的那样具体的东西.我有两个不同的表,我需要从中获取信息.这是一个示例架构-与我正在使用的架构类似:

Ok, I've searched but can't find anything as specific as I'm trying to do here. I have two different tables that I need info from. This is a sample schema - similar to what I'm working from:

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左右.我所知道的是这样写的:

I'm attempting to write a query (with a where clause...will have multiple a filters on final version) that will return Node.Caption, IP_Address, and every Volumes.Caption associated (based on NodeID). The number of entries in Volumes.Caption for each NodeID is dynamic and varies from 1 to about 60 or so. All I know how to write is this:

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和所有匹配的Volumes(如果可能).像这样(最后一列的名称并不重要...可以是任何东西):

But what I need is a single ROW per NodeID showing Node.Caption, IP_Address and all matching Volumes if possible. Like this (the final column names are not important...can be anything):

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个枢轴示例,因此我想展示一种可以做到这一点的方法,虽然不如枢轴好,但可以为您的实例服务.它可能不适合您的整个数据集,并且仅基于示例数据.

There's 100 pivot examples on SO so I wanted to show a way that you could do this, which isn't as good as pivot, but works for your instance. It may not fit your entire dataset and was based on your sample data only.

值得注意的是,您的测试数据并未提供您声称的结果.可能只是插入内容上的错字.

Of note, your test data doesn't provide the results you claim they do. Probably just a typo on the insert.

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

这篇关于SQL-将列转置为行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆