Link to home
Start Free TrialLog in
Avatar of batdan
batdan

asked on

Pivot (Cross-tab query) in T-SQL

Hi.

I have a simple table looking something like the following:

Date     ID     Value
--------------------------
21/03/2003  a  12
21/03/2003  b  54
21/03/2003  c  32
22/03/2003  a  76
22/03/2003  b  34
22/03/2003  c  1
23/03/2003  a  72
23/03/2003  b  42
23/03/2003  c  65

I'm trying to query the data so the result will look like the following:

Date     a     b     c
--------------------------
21/03/2003  12  54  32
22/03/2003  76  34  1
23/03/2003  72  42  65

I've found that I can use the following T-SQL to do this:

SELECT [Date],
    SUM(CASE [ID] WHEN 1 THEN [value] ELSE 0 END) AS a,
    SUM(CASE [ID] WHEN 2 THEN [value] ELSE 0 END) AS b,
    SUM(CASE [ID] WHEN 3 THEN [value] ELSE 0 END) AS c
FROM Table1
GROUP BY [Date]

The only problem with this is that if a record is added for a date with the ID of d or whatever, then I'll need to adjust the query to cope with it.  Does anyone know of a generic query that I can use to cope with extra ID's being added with having to alter the T-SQL?

Thanks in advance
Avatar of Lowfatspread
Lowfatspread
Flag of United Kingdom of Great Britain and Northern Ireland image

I think the following should work, and construct for you
the generic case...

Declare @sql varchar(8000)
Declare @startid char(1)
set @startid=' '
Set @sql=' Select [date] '

while exists (select top 1 [id] from table1 where [id] > @startid)

begin
Select top 1 @sql=@sql + ','
'Sum(case [id] when ' + [id] + ' then 1 else 0 end) as [' + [id] + ']', @startid=[id]
 from table1 where [id] > @startid
end

set @sql=@sql + ' from table1 group by [date]'

Exec (@sql)



it would probably be better if you established the
query for the set you currently know of (a,b,c)
and then alter the queries to exclude these values as well so that at least you initially only do 1 select  


hth
Avatar of dmeili
dmeili

Well, if you want a script just for this specific table, then do this:

declare @numID int, @i int
@sql varchar(300)

select @numID=[id] from table1 group by [id]
select @i=1
select @sql='SELECT [Date],'
while @i<=@numID
  begin
   select @sql=@sql+'SUM(CASE [ID] WHEN ' + convert(varchar(2),@i) + ' THEN [value] ELSE 0 END) AS '+char(64+@i)+
','
  end
select @sql=left(@sql,len(@sql)-1)
select @sql=@sql+' FROM Table1 GROUP BY [Date]'
exec(@sql)
Avatar of batdan

ASKER

Hi, thanks for the replies.

LowFatSpread:

The query executes but I've had to stop it 10 minutes through as it still hasn't returned any records.  Is this just a very slow query of could there be something else wrong?

keystrokes:

When I try to run this I'm getting an error which states:
Syntax error converting the varchar value 'a' to a column of data type int.

Also please bear in mind (sorry I should have mentioned this) that the ID field values in the actual table are likely to be a variable length string which could also include spaces and not necessarily ordered.

dmeilli:
Thanks for the link, but this isn't exactly what I was looking for.

Any further help appreciated.
ASKER CERTIFIED SOLUTION
Avatar of Lowfatspread
Lowfatspread
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
batdan:
This old question needs to be finalized -- accept an answer, split points, or get a refund.  For information on your options, please click here-> http:/help/closing.jsp#1 
EXPERTS:
Post your closing recommendations!  No comment means you don't care.
Avatar of batdan

ASKER

Sorry for the extreme delay in accepting this answer, and thanks for all the help.
I am suprised that no one here knew how to build a crosstab query.
here is the syntax for a crossdab query example


SELECT CategoryField, *
FROM
(
SELECT RE.*, B.CategoryField
FROM
      Tale RE
      INNER JOIN
            dbo.OtherTable B
            ON RE.RecID= B.RecID
) a
PIVOT
(
SUM(Amount)
FOR SomeFieldYear
IN ([2010],[2011])
)
AS p