Performance is king. But what few seem to be aware of is what is
left in its wake. And what could possibly be good about something
"Greg Linwood" <g_linwood@hotmail.com> wrote in message
news:elWYv74uHHA.3816@TK2MSFTNGP05.phx.gbl...
> If you need a good option for doing dynamic crosstab, Geckoware's crosstab
> builder does a great job of dynamically building crosstab queries.
>
http://www.geckoware.com.au/
>
> This tool is much more efficient than temp tables / table variables as its
> an in-proc dll (xp_) which works in memory rather than on disk (as temp
> objects do).
>
> Regards,
> Greg Linwood
> SQL Server MVP
>
http://blogs.sqlserver.org.au/blogs/greg_linwood
> Benchmark your query performance
>
http://www.SQLBenchmarkPro.com >
> "Erland Sommarskog" <esquel@sommarskog.se> wrote in message
> news:Xns995FF0D84A6D0Yazorman@127.0.0.1...
>> Debbie Croft (debbie.croft@nospamforme.com) writes:
>>> I have a database that has a table similar to the following:
>>>
>>> ID Company Year Value
>>> ----------------------
>>> 1 CompanyA 1998 378
>>> 2 CompanyB 1998 45
>>> 3 CompanyC 1998 245
>>> 4 CompanyA 1999 754
>>> 5 CompanyB 1999 298
>>> 6 CompanyC 1999 7
>>> 7 CompanyA 2000 347
>>> 8 CompanyB 2000 32
>>> 9 CompanyC 2000 186
>>>
>>> I'd like to output this as:
>>>
>>> Company 1998 1999 2000
>>> -----------------------
>>> CompanyA 378 754 347
>>> CompanyB 45 298 32
>>> CompanyC 245 7 186
>>>
>>> The problem is that I'd don't know before hand what years are in the
>>> database - they change as new data is added.
>>>
>>> What's the best way to write a query that performs this transformation?
>>> Can it be done using set logic (i.e. without procedural code)?
>>
>> A SELECT query produces a table. A table has column with known names, and
>> therefore also the number of column must be known. Thus, if there can be
>> any number of years in the table, you cannot write this in a single
>> SELECT.
>> If you can assume that there are at most, say, three years, you can write
>> it as a query, but you need to accept that the year cannot be indicated
>> in the column header, but that will have to be a separate column.
>>
>> Here is a query for SQL 2005 that produces this:
>>
>> CREATE TABLE somevalues (Company varchar(12) NOT NULL,
>> year char(4) NOT NULL,
>> value int NOT NULL,
>> PRIMARY KEY (Company, year))
>> go
>> INSERT somevalues (Company, year, value)
>> SELECT 'CompanyA', '1998', 378 UNION ALL
>> SELECT 'CompanyB', '1998', 45 UNION ALL
>> SELECT 'CompanyC', '1998', 245 UNION ALL
>> SELECT 'CompanyA', '1999', 754 UNION ALL
>> SELECT 'CompanyB', '1999', 298 UNION ALL
>> SELECT 'CompanyC', '1999', 7 UNION ALL
>> SELECT 'CompanyA', '2000', 347 UNION ALL
>> SELECT 'CompanyB', '2000', 32 UNION ALL
>> SELECT 'CompanyC', '2000', 186
>> go
>> SELECT Company,
>> Year1 = MIN(CASE y.rn WHEN 1 THEN s.year END),
>> Value_year1 = MIN(CASE y.rn WHEN 1 THEN s.value END),
>> Year2 = MIN(CASE y.rn WHEN 2 THEN s.year END),
>> Value_year3 = MIN(CASE y.rn WHEN 2 THEN s.value END),
>> Year3 = MIN(CASE y.rn WHEN 3 THEN s.year END),
>> Value_year2 = MIN(CASE y.rn WHEN 3 THEN s.value END)
>> FROM somevalues s
>> JOIN (SELECT DISTINCT year,
>> rn = dense_rank() OVER (ORDER BY year)
>> FROM somevalues) AS y ON s.year = y.year
>> GROUP BY Company
>> go
>> DROP TABLE somevalues
>>
>>
>> If you absolute must have the column names dynamic and/or have a
>> dynamic set of columns, you must build the query dynamically and
>> execute it with sp_executesql. This is quite steep increase in
>> complexity.
>>
>>
>>
>> --
>> Erland Sommarskog, SQL Server MVP, esquel@sommarskog.se
>>
>> Books Online for SQL Server 2005 at
>>
http://www.microsoft.com/technet/prodtechnol/sql/2005/downloads/books.mspx >> Books Online for SQL Server 2000 at
>>
http://www.microsoft.com/sql/prodinfo/previousversions/books.mspx >
>