Sql : Select A Dynamic Number Of Rows As Columns
Solution 1:
Do this in the client.
SQL is a fixed column language: you can't have a varible number of columns (even with PIVOT etc). Dynamic SQL is not a good idea.
Solution 2:
What you require is a pivot query, to convert row data into columnar:
SELECT t.hotelid,
t.blockid,
t.blockname,
MAX(CASEWHEN t2.blockdate ='02-10-10'THEN t.numberofrooms ELSENULLEND) AS02_10_10,
MAX(CASEWHEN t2.blockdate ='02-11-10'THEN t.numberofrooms ELSENULLEND) AS02_11_10,
MAX(CASEWHEN t2.blockdate ='02-12-10'THEN t.numberofrooms ELSENULLEND) AS02_12_10,
...
FROM TABLE_1 t
JOIN TABLE_2 t2
GROUPBY t.hotelid, t.blockid, t.blockname
Mind that there's nothing to link the tables - realistically
TABLE_2needshotelidandblockidattributes. As-is, this will return the results ofTABLE_2for every record inTABLE_1...The database is important, because it will need dynamic SQL to create the
MAX(CASE...statements
Solution 3:
you are missing a foreign key. I have to assume that BlockId should be PK in table 2?
Also, assuming that this is a legacy db and changing the structure is not an option, i have to ask which platform?
If ms sql, this could easily be achieved using a dynamic sql statement.
Solution 4:
I once wrote a stored procedure that did just something like this. Given are a users table with basic details and a variable number of profile properties for users. (The number of profile properties varies per DotNetNuke Portal)
This is straight from DotNetNuke 4.9, check the database schema from there and you'll get the details. Tables involved are Users, UserPortals, UserProfile, ProfilePropertyDefinition
In short words :
- I create a temp table with all the profile properties as columns (dynamically)
- I fill the temp table with userid (as foreign key to link to users table and all the profile properties data
- I do a join on users table and temp table
This gives me one row per user with all profile properties.
Here the code - not perfect but hey its tailored for my needs but should be easy enough to re-use (tried to avoid cursors btw)
set ANSI_NULLS ONset QUOTED_IDENTIFIER ON
go
ALTERPROCEDURE [dbo].[rows2cols] @portalIdINTASBEGIN
print 'PortalID='+convert(varchar,@portalId)
--SET NOCOUNT ON;declare@idxintdeclare@rowcountintdeclare@tmpStr nvarchar(max)
declare@ctype nvarchar(max)
declare@cname nvarchar(max)
declare@clenintdeclare@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'))
DROPTABLE [dbo].[xxxx]
print 'Building Temp Table Cols for profile properties...'set@rowcount= (selectcount(*) from ProfilePropertyDefinition where PortalID=0and deleted=0)
set@idx=1set@tmpStr=''
while (@idx<=@rowcount)
begin-- dynamically generate rownumbers to be able to do loop over them (avoid cursors)select@cname= t1.PropertyName from
( selectROW_NUMBER() OVER (ORDERBY ViewOrder) as Idx, PropertyName from ProfilePropertyDefinition
where PortalID=0and deleted=0
) as t1 where t1.Idx =@idx
if (@cname='Email'or@cname='FirstName'or@cname='LastName') beginset@clen=1endelsebeginset@tmpStr=@tmpStr+'['+@cname+'] [nvarchar](500), 'endset@idx=@idx+1endset@tmpStr=@tmpStr+'[userid] [int] 'set@createStr='create table xxxx ( '+@tmpStr+' )'
Print @createStrExec (@createStr)
----------------------------------------------------------------------------- fill tmp table ----------------------------------------------------------------------------- declare@propName nvarchar(max)
declare@propVal nvarchar(max)
declare@userIdintdeclare@idx2intdeclare@rowcount2intdeclare@inscol nvarchar(max)
declare@insval nvarchar(max)
set@rowcount= (selectcount(*) FROM Users LEFTOUTERJOIN UserPortals ON Users.UserID = UserPortals.UserId WHERE UserPortals.PortalId =@portalId)
set@idx=1
while (@idx<=@rowcount)
begin-- get userIdselect@userId= t1.UserID from (select u.UserID, ROW_NUMBER() OVER (ORDERBY u.UserID) as Idx
from Users as u LEFTOUTERJOIN UserPortals as up ON u.UserID = up.UserId where up.PortalId =@portalId) as t1
where t1.Idx =@idxset@idx2=1set@rowcount2= (selectcount(*) from UserProfile where UserID =@userId)
set@inscol=''set@insval=''
while (@idx2<@rowcount2)
begin-- build insert for a specific userselect@propName= t1.PropertyName , @propVal=t1.PropertyValue from
( selectROW_NUMBER() OVER (ORDERBY ProfileID) as Idx, up.PropertyDefinitionID,ppd.PropertyName, up.PropertyValue
from UserProfile as up
innerjoin 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')
beginset@inscol=@inscol+@propName+', 'set@insval=@insval+'N'''+ replace(@propVal,'''','''''') +''', 'endset@idx2=@idx2+1endset@inscol=@inscol+'userid'set@insval=@insval+convert(nvarchar,@userId)
set@tmpStr='insert into xxxx ('+@inscol+') values ('+@insval+')'--print @tmpStrExec(@tmpStr)
set@idx=@idx+1end-- --------------------------------------------------------------------------- return tmp table & dump ---- ------------------------------------------------------------------------- SELECT Users.*, xxxx.*FROM xxxx INNERJOIN 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'))
DROPTABLE [dbo].[xxxx]
END
Post a Comment for "Sql : Select A Dynamic Number Of Rows As Columns"