我需要选择静态列+动态行数作为SQL
中的列TABLE 1
-------
HotelID
BlockID
BlockName
TABLE 2
-------
BlockDate (unknown number of these)
NumberOfRooms
Desired Result Row
------------------
HotelID | BlockID | BlockName | 02/10/10 | 02/11/10 | 02/12/10 | ...N
其中日期列是未知数量的封锁行。
答案 0 :(得分:2)
在客户端执行此操作。
SQL是一种固定的列语言:您不能拥有可变数量的列(即使使用PIVOT等)。动态SQL不是一个好主意。
答案 1 :(得分:1)
您需要的是一个数据透视查询,用于将行数据转换为柱状数据:
SELECT t.hotelid,
t.blockid,
t.blockname,
MAX(CASE WHEN t2.blockdate = '02-10-10' THEN t.numberofrooms ELSE NULL END) AS 02_10_10,
MAX(CASE WHEN t2.blockdate = '02-11-10' THEN t.numberofrooms ELSE NULL END) AS 02_11_10,
MAX(CASE WHEN t2.blockdate = '02-12-10' THEN t.numberofrooms ELSE NULL END) AS 02_12_10,
...
FROM TABLE_1 t
JOIN TABLE_2 t2
GROUP BY t.hotelid, t.blockid, t.blockname
请注意,没有任何内容可以链接表格 - 实际上TABLE_2
需要hotelid
和blockid
属性。按原样,这将为TABLE_2
中的每条记录返回TABLE_1
的结果...
数据库很重要,因为它需要动态SQL来创建MAX(CASE...
语句
答案 2 :(得分:0)
你错过了一个外键。我必须假设BlockId应该是表2中的PK?
另外,假设这是遗留数据库并且不能改变结构,我不得不问哪个平台?
如果使用ms sql,可以使用动态sql语句轻松实现。
答案 3 :(得分:0)
我曾经写过一个存储过程就是这样做的。给定的是具有基本详细信息和用户可变数量的配置文件属性的用户表。 (配置文件属性的数量因DotNetNuke Portal而异)
这是直接来自DotNetNuke 4.9,从那里检查数据库架构,你会得到详细信息。涉及的表是Users,UserPortals,UserProfile,ProfilePropertyDefinition
简而言之:
这为每个用户提供了一行所有配置文件属性。
这里的代码 - 不完美,但是它根据我的需求量身定做,但应该很容易重复使用(试图避免使用游标)
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[rows2cols] @portalId INT
AS BEGIN
print 'PortalID=' + convert(varchar,@portalId)
--SET NOCOUNT ON;
declare @idx int
declare @rowcount int
declare @tmpStr nvarchar(max)
declare @ctype nvarchar(max)
declare @cname nvarchar(max)
declare @clen int
declare @createStr nvarchar(max)
---------------------------------------------------------------------------
-- create tmp table --
---------------------------------------------------------------------------
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[xxxx]') AND type in (N'U'))
DROP TABLE [dbo].[xxxx]
print 'Building Temp Table Cols for profile properties...'
set @rowcount = (select count(*) from ProfilePropertyDefinition where PortalID=0 and deleted=0)
set @idx = 1
set @tmpStr = ''
while (@idx <= @rowcount)
begin
-- dynamically generate rownumbers to be able to do loop over them (avoid cursors)
select @cname = t1.PropertyName from
( select ROW_NUMBER() OVER (ORDER BY ViewOrder) as Idx, PropertyName from ProfilePropertyDefinition
where PortalID=0 and deleted=0
) as t1 where t1.Idx = @idx
if (@cname = 'Email' or @cname = 'FirstName' or @cname = 'LastName') begin
set @clen = 1
end else begin
set @tmpStr = @tmpStr + '[' + @cname + '] [nvarchar](500), '
end
set @idx = @idx + 1
end
set @tmpStr = @tmpStr + '[userid] [int] '
set @createStr = 'create table xxxx ( ' + @tmpStr + ' )'
Print @createStr
Exec (@createStr)
---------------------------------------------------------------------------
-- fill tmp table --
---------------------------------------------------------------------------
declare @propName nvarchar(max)
declare @propVal nvarchar(max)
declare @userId int
declare @idx2 int
declare @rowcount2 int
declare @inscol nvarchar(max)
declare @insval nvarchar(max)
set @rowcount = (select count(*) FROM Users LEFT OUTER JOIN UserPortals ON Users.UserID = UserPortals.UserId WHERE UserPortals.PortalId = @portalId)
set @idx = 1
while (@idx <= @rowcount)
begin
-- get userId
select @userId = t1.UserID from (select u.UserID, ROW_NUMBER() OVER (ORDER BY u.UserID) as Idx
from Users as u LEFT OUTER JOIN UserPortals as up ON u.UserID = up.UserId where up.PortalId = @portalId) as t1
where t1.Idx = @idx
set @idx2 = 1
set @rowcount2 = (select count(*) from UserProfile where UserID = @userId)
set @inscol = ''
set @insval = ''
while (@idx2 < @rowcount2)
begin
-- build insert for a specific user
select @propName = t1.PropertyName , @propVal=t1.PropertyValue from
( select ROW_NUMBER() OVER (ORDER BY ProfileID) as Idx, up.PropertyDefinitionID,ppd.PropertyName, up.PropertyValue
from UserProfile as up
inner join ProfilePropertyDefinition as ppd on up.PropertyDefinitionID = ppd.PropertyDefinitionID
where UserID = @userId
) as t1 where t1.Idx = @idx2
if (@propName != 'Firstname' and @propName != 'LastName' and @propName != 'Email')
begin
set @inscol = @inscol + @propName + ', '
set @insval = @insval + 'N''' + replace(@propVal,'''','''''') + ''', '
end
set @idx2 = @idx2 + 1
end
set @inscol = @inscol + 'userid'
set @insval = @insval + convert(nvarchar,@userId)
set @tmpStr = 'insert into xxxx (' + @inscol + ') values (' + @insval + ')'
--print @tmpStr
Exec(@tmpStr)
set @idx = @idx + 1
end
-- -------------------------------------------------------------------------
-- return tmp table & dump --
-- -------------------------------------------------------------------------
SELECT Users.*, xxxx.* FROM xxxx INNER JOIN Users ON xxxx.userid = Users.UserID
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[xxxx]') AND type in (N'U'))
DROP TABLE [dbo].[xxxx]
END