Reputation: 45
Please find below the script. I am trying to call the column names dynamically. The first 3 columns are LOC
, Product
and status
are fixed. There are 53 columns atfer that from 2015 and for 2016 like: 1-2015
, 2-2015
, 3-2015
... 53-2015
and 1-2016
, 2-2016
, 3-2016
... 53-2016
. I want to build dynamic SQL to call all that columns. I am doing this because I want it in specific order which i'm not able to get if i use SELECT * FORM TABLE.
declare @values varchar(max)
declare @n varchar(10)
set @n = 1
set @values = '
SELECT[LOC]
,[PRODUCT]
,[STATUS]
,['+@n+'-2015]
,['+@n+'-2016]
FROM [LGI_Temp].[dbo].[Temp_PIVOT]';
exec(@values);
This gives me result like:
LOC PRODUCT STATUS 1-2015 1-2016
I want it for all the 53 values in each year.
How to do that?
Upvotes: 0
Views: 1346
Reputation: 33571
Using a tally table is a better approach here than looping. Sure this loop is small and not likely to cause a lot of performance problems but the tally table is so simple it should be used here. My personal favorite article explaining tally tables can be found over at sql server central. http://www.sqlservercentral.com/articles/T-SQL/62867/
Taking the code that Bogdan Bogdanov posted here is how you would convert that to using a tally table instead of a loop.
First you need the tally table. I do this in my system with a view.
create View [dbo].[cteTally] as
WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select N from cteTally
GO
Now that it is a view I don't have to worry about writing it again. Just use it.
DECLARE @SqlCmd VARCHAR(MAX);
SET @SqlCmd = 'SELECT [LOC], [PRODUCT], [STATUS] ';
select @SqlCmd = @SqlCmd + ', [' + cast(N as varchar(2)) + '-2015], [' + cast(N as varchar(2)) + '-2016]'
from cteTally
where N <= 53
SET @SqlCmd = @SqlCmd + ' FROM [LGI_Temp].[dbo].[Temp_PIVOT];'
select @SqlCmd
The bigger issue here as I see it is that this table is horrible denormalized. Instead of a column for each month you should have a date column...although from the name this looks to be a permanent "temp" table used for a pivot. There are better ways of dynamically converting rows to columns. Around this site people like the Dynamic Pivot. I personally prefer a dynamic cross tab but that is a preference thing. I find the syntax for a cross tab less obtuse and there is even a slight performance benefit from it.
Upvotes: 3
Reputation: 1723
Ok, try this:
DECLARE @SqlCmd VARCHAR(MAX);
DECLARE @colN VARCHAR(10);
SET @SqlCmd = 'SELECT [LOC], [PRODUCT], [STATUS] ';
SET @colN = 1;
WHILE (@colN < 54)
BEGIN
SET @SqlCmd = @SqlCmd + ',[' + @colN + '-2015],[' + @colN + '-2016]';
SET @colN = @colN + 1;
END;
SET @SqlCmd = @SqlCmd + ' FROM [LGI_Temp].[dbo].[Temp_PIVOT];'
EXEC (@SqlCmd);
REMARK: This is not the best solution. I just try to show an quick example. See comment of @Sean Lange bellow.
Upvotes: 0