use*_*979 1 sql-server-2008 pivot
我创建了一个包含以下 2 个小表的数据库
这是数据库脚本
USE [Test1July]
GO
/****** Object: Table [dbo].[Hotels] Script Date: 07/01/2014 22:33:33 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Hotels](
[SeqID] [int] IDENTITY(1,1) NOT NULL,
[HotelName] [nchar](25) NULL,
CONSTRAINT [PK_Hotels] PRIMARY KEY CLUSTERED
(
[SeqID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object: Table [dbo].[HotelRooms] Script Date: 07/01/2014 22:33:33 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[HotelRooms](
[SeqID] [int] IDENTITY(1,1) NOT NULL,
[HotelSeqID] [int] NOT NULL,
[FloorNo] [int] NOT NULL,
[RoomNo] [int] NOT NULL,
[Beds] [int] NOT NULL
) ON [PRIMARY]
GO
/****** Object: StoredProcedure [dbo].[GetFloorStructure] Script Date: 07/01/2014 22:33:34 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[GetFloorStructure](
@HotelSeqID INT
)
AS
BEGIN
SELECT HotelRooms.FloorNo, HotelRooms.RoomNo, HotelRooms.Beds
FROM HotelRooms INNER JOIN
Hotels ON HotelRooms.HotelSeqID = Hotels.SeqID
WHERE (HotelRooms.HotelSeqID = @HotelSeqID)
END
GO
/****** Object: ForeignKey [FK_HotelRooms_Hotels] Script Date: 07/01/2014 22:33:33 ******/
ALTER TABLE [dbo].[HotelRooms] WITH CHECK ADD CONSTRAINT [FK_HotelRooms_Hotels] FOREIGN KEY([HotelSeqID])
REFERENCES [dbo].[Hotels] ([SeqID])
GO
ALTER TABLE [dbo].[HotelRooms] CHECK CONSTRAINT [FK_HotelRooms_Hotels]
GO
Run Code Online (Sandbox Code Playgroud)
我正在寻找一种解决方案,显示酒店楼层的楼层结构,显示房间数据,如 roomNo 和床位,而不是垂直 - 即我应该能够查看特定数据的 1 楼的单行数据。我一直在尝试使用动态 PIVOT,但我对 PIVOT 的了解非常有限。
我设法创建了一个动态 PIVOT 查询,但没有得到预期的结果。请建议如何在动态生成的列中实现单行中的多行结果 - 这是我的查询
DECLARE @colsPivot AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @colsPivot = STUFF((SELECT ',' + QUOTENAME(c.col + '_'+cast(rn as varchar(10)))
from
(
select row_number() over(partition by FloorNo, RoomNo
order by Beds) rn
from HotelRooms
) t
cross apply
(
select 'Beds' col, 1 so union all
select 'HotelSeqID', 2
) c
group by col, rn, so
order by rn, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query
= 'select FloorNo, RoomNo, '+@colsPivot+'
from
(
select FloorNo, RoomNo,
col+''_''+cast(rn as varchar(10)) col,
val
from
(
select FloorNo, RoomNo, Beds, HotelSeqID
, row_number() over(partition by FloorNo, RoomNo
order by Beds) rn
from HotelRooms
) d
unpivot
(
val
for col in (Beds, HotelSeqID)
) un
) s
pivot
(
max(val)
for col in ('+ @colspivot +')
) p'
exec(@query);
Run Code Online (Sandbox Code Playgroud)
这是我从一个简单的选择查询中得到的输出
FloorNo RoomNo Beds
1 101 1
1 102 2
1 103 1
1 104 2
2 201 1
2 202 2
2 203 1
2 204 2
2 205 1
2 206 2
Run Code Online (Sandbox Code Playgroud)
但我想要这种格式的输出
FloorNo RoomNo Beds RoomNo Beds RoomNo Beds
1 101 1 102 2 103 1
Run Code Online (Sandbox Code Playgroud)
这是查询的 STATIC 版本,它为我提供了所需的结果
select HotelSeqID, FloorNo,
max(case when rn = 1 then RoomNo end) RoomNo,
max(case when rn = 1 then Beds end) Beds,
max(case when rn = 2 then RoomNo end) RoomNo,
max(case when rn = 2 then Beds end) Beds,
max(case when rn = 3 then RoomNo end) RoomNo,
max(case when rn = 3 then Beds end) Beds,
max(case when rn = 4 then RoomNo end) RoomNo,
max(case when rn = 4 then Beds end) Beds,
max(case when rn = 5 then RoomNo end) RoomNo,
max(case when rn = 5 then Beds end) Beds
from
(
select HotelSeqID, FloorNo, RoomNo, Beds,
row_number() over(partition by HotelSeqID ORDER BY FloorNo) rn
from HotelRooms
WHERE (HotelRooms.HotelSeqID = @HotelSeqID)
) src
group by HotelSeqID, FloorNo;
Run Code Online (Sandbox Code Playgroud)
我只需要这个查询的动态版本 -
由于您想使用它PIVOT
来获取结果并且需要动态地获取结果,因此我始终建议先编写静态 PIVOT 查询,这样您就可以在尝试将其转换为动态 SQL 之前获得正确的语法。
所需的输出显示,要在两列PIVOT,RoomNo
和Beds
-作为一个结果,你需要先UNPIVOT这些列,然后应用的枢纽。
您当前的查询是在正确的轨道上,您确实需要使用,row_number()
以便您可以获得每层楼的房间/床位数量 - 但您的逆枢轴正在使用Beds
和HotelSeqID
。您不想取消透视,HotelSeqID
因为它没有您最终想要作为新列的值。
我会通过以下方式启动一个静态版本 - 首先是子查询从你的表中垂直获取数据,row_number()
包括:
select h.HotelName,
r.FloorNo,
r.RoomNo,
r.Beds,
seq = row_number() over(partition by h.HotelName, r.FloorNo
order by r.RoomNo)
from dbo.Hotels h
inner join dbo.HotelRooms r
on h.seqid = r.hotelseqid
Run Code Online (Sandbox Code Playgroud)
请参阅SQL Fiddle with Demo。您的数据将如下所示,其中包含基于HotelName
和的序列号的新列FloorNo
:
| HOTELNAME | FLOORNO | ROOMNO | BEDS | SEQ |
|---------------------------|---------|--------|------|-----|
| Hotel 1 | 1 | 101 | 1 | 1 |
| Hotel 1 | 1 | 102 | 2 | 2 |
| Hotel 1 | 1 | 103 | 1 | 3 |
| Hotel 1 | 1 | 104 | 2 | 4 |
| Hotel 1 | 2 | 201 | 1 | 1 |
| Hotel 1 | 2 | 202 | 2 | 2 |
Run Code Online (Sandbox Code Playgroud)
现在,您可以将RoomNo
和Beds
列反透视为多行。由于您使用的是 SQL Server 2008,因此您可以使用它CROSS APPLY
来获取结果。查询将是:
select hr.HotelName,
hr.FloorNo,
col = c.col + '_' + cast(seq as varchar(2)),
c.val
from
(
select h.HotelName,
r.FloorNo,
r.RoomNo,
r.Beds,
seq = row_number() over(partition by h.HotelName, r.FloorNo
order by r.RoomNo)
from dbo.Hotels h
inner join dbo.HotelRooms r
on h.seqid = r.hotelseqid
) hr
cross apply
(
select 'RoomNo', RoomNo union all
select 'Beds', Beds
) c (col, val);
Run Code Online (Sandbox Code Playgroud)
请参阅SQL Fiddle with Demo。您的数据现已转换为多列:
| HOTELNAME | FLOORNO | COL | VAL |
|---------------------------|---------|----------|-----|
| Hotel 1 | 1 | RoomNo_1 | 101 |
| Hotel 1 | 1 | Beds_1 | 1 |
| Hotel 1 | 1 | RoomNo_2 | 102 |
| Hotel 1 | 1 | Beds_2 | 2 |
| Hotel 1 | 1 | RoomNo_3 | 103 |
| Hotel 1 | 1 | Beds_3 | 1 |
| Hotel 1 | 1 | RoomNo_4 | 104 |
| Hotel 1 | 1 | Beds_4 | 2 |
| Hotel 1 | 2 | RoomNo_1 | 201 |
Run Code Online (Sandbox Code Playgroud)
最后,您可以旋转以获得最终结果。
select HotelName, FloorNo,
RoomNo_1, Beds_1, RoomNo_2, Beds_2,
RoomNo_3, Beds_3, RoomNo_4, Beds_4
from
(
select hr.HotelName,
hr.FloorNo,
col = c.col + '_' + cast(seq as varchar(2)),
c.val
from
(
select h.HotelName,
r.FloorNo,
r.RoomNo,
r.Beds,
seq = row_number() over(partition by h.HotelName, r.FloorNo
order by r.RoomNo)
from dbo.Hotels h
inner join dbo.HotelRooms r
on h.seqid = r.hotelseqid
) hr
cross apply
(
select 'RoomNo', RoomNo union all
select 'Beds', Beds
) c (col, val)
) d
pivot
(
max(val)
for col in (RoomNo_1, Beds_1, RoomNo_2, Beds_2,
RoomNo_3, Beds_3, RoomNo_4, Beds_4)
) piv
order by HotelName, FloorNo;
Run Code Online (Sandbox Code Playgroud)
请参阅SQL Fiddle with Demo。一旦您测试了静态版本以确保它获得您想要的结果,您就可以轻松地将其转换为动态 SQL。
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(col + '_' + cast(seq as varchar(2)))
from
(
select seq = row_number() over(partition by h.HotelName, r.FloorNo
order by r.RoomNo)
from dbo.Hotels h
inner join dbo.HotelRooms r
on h.seqid = r.hotelseqid
) d
cross apply
(
select 'RoomNo', 1 union all
select 'Beds', 2
) c (col, so)
group by col, so, seq
order by seq, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = N'SELECT HotelName, FloorNo,' + @cols + N'
from
(
select hr.HotelName,
hr.FloorNo,
col = c.col + ''_'' + cast(seq as varchar(2)),
c.val
from
(
select h.HotelName,
r.FloorNo,
r.RoomNo,
r.Beds,
seq = row_number() over(partition by h.HotelName, r.FloorNo
order by r.RoomNo)
from dbo.Hotels h
inner join dbo.HotelRooms r
on h.seqid = r.hotelseqid
) hr
cross apply
(
select ''RoomNo'', RoomNo union all
select ''Beds'', Beds
) c (col, val)
) x
pivot
(
max(val)
for col in (' + @cols + N')
) p
order by HotelName, FloorNo'
exec sp_executesql @query
Run Code Online (Sandbox Code Playgroud)
请参阅SQL Fiddle with Demo。此查询将为您提供结果:
| HOTELNAME | FLOORNO | ROOMNO_1 | BEDS_1 | ROOMNO_2 | BEDS_2 | ROOMNO_3 | BEDS_3 | ROOMNO_4 | BEDS_4 | ROOMNO_5 | BEDS_5 | ROOMNO_6 | BEDS_6 |
|---------------------------|----------|-----------|--------|----------|--------|----------|--------|----------|--------|----------|--------|----------|--------|
| Hotel 1 | 1 | 101 | 1 | 102 | 2 | 103 | 1 | 104 | 2 | (null) | (null) | (null) | (null) |
| Hotel 1 | 2 | 201 | 1 | 202 | 2 | 203 | 1 | 204 | 2 | 205 | 1 | 206 | 2 |
| Hotel 2 | 1 | 101 | 4 | 102 | 6 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |
| Hotel 2 | 2 | 201 | 2 | 202 | 7 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
10997 次 |
最近记录: |