July 25, 2006 at 2:04 pm
I want to PIVOT tables where it is not necessary to sum or count or otherwise aggregate data. Every example of using PIVOT that I can find includes pivoting on an aggregate function, e.g. PIVOT(SUM(somevalue)...is there a way to use PIVOT without an aggregate function? I have not been able to get it to work.
July 25, 2006 at 2:28 pm
Can you post a sample of what you are trieng to do ? DDL/Data/Result required
Vasc
July 25, 2006 at 2:29 pm
To my knowledge pivet needs a aggregate function. Without aggregate function logically it is not needed. can you explain specfic need.
Also it will be more rows something like this.
SET NOCOUNT ON
DECLARE @Tbl TABLE
(
MyID INT,
MyVal VARCHAR(10)
)
INSERT @Tbl
SELECT '1', 'AA' UNION
SELECT '2', 'BB' UNION
SELECT '3', 'CC' UNION
SELECT '4', 'DD' UNION
SELECT '5', 'EE'
SELECT Col1 = CASE WHEN MyVal = 'AA' THEN MyID ELSE NULL END,
Col2 = CASE WHEN MyVal = 'BB' THEN MyID ELSE NULL END,
Col3 = CASE WHEN MyVal = 'CC' THEN MyID ELSE NULL END,
Col4 = CASE WHEN MyVal = 'DD' THEN MyID ELSE NULL END,
Col5 = CASE WHEN MyVal = 'EE' THEN MyID ELSE NULL END
FROM
@Tbl
Regards,
gova
July 25, 2006 at 2:40 pm
Bruce might mean an ordinary transform of a resultset. Changing rows to columns and columns to rows.
Take a moment or two and read my recent article here
http://www.sqlservercentral.com/columnists/plarsson/pivottableformicrosoftsqlserver.asp
That might give you an idea of how to accomplish your task without aggregation.
N 56°04'39.16"
E 12°55'05.25"
July 25, 2006 at 3:08 pm
Thank you Peter, I read the article. The thing is, we have need of dozens of such procs and I would like to keep it simple, hence my desire to use PIVOT.
Here is more information. The first thing you will notice is that tblProperties is all wrong, but we don’t know what kinds of properties will be added in the future, so cannot create columns for them. So, we have a bunch of tables like this one.
tblProperties:
AircraftPropertyNameValue
1 Hours1200
1 Landings900
1 Seats2
1 Engines 2
I can get the result below with the following statement (more or less, I changed things to make the table readable and hope I “translated” my original query property – in any case you get the idea):
SELECT Aircraft, Hours, Landings, Seats, Engines
FROM (SELECT Aircraft, PropertyName, Value FROM tblProperties) As PivotProperties
PIVOT (MAX(Value) FOR Aircraft In (Hours, Landings, Seats, Engines) As pvt
For result:
Aircraft HoursLandingsSeatsEngines
1120090022
Here’s the catch – there cannot be dupes in the table; that is, Aircraft 1 will never have more than one record of "Hours," and therefore there is nothing to aggregate. All I want to do is pivot the data without the “MAX” in there. I saw the following in the SQL Server 2005 Books online, which suggests that it is possible to PIVOT without aggregating, but I’ve not been able to make it work (“Using PIVOT and UNPIVOT”): “When using aggregate functions with PIVOT, the presence of any NULL values in the value column are not considered when computing an aggregation.” This certainly implies that aggregating with PIVOT is optional, but I sure can’t find any examples or figure out the syntax myself.
Suggestions are welcome, thanks.
Bruce
July 25, 2006 at 3:25 pm
You can not use PIVOT for SQL 2005 since you need to hardwire the columns.
Your choice of method is dynamic SQL.
And selecting MAX of 1 record is very fast!
N 56°04'39.16"
E 12°55'05.25"
July 25, 2006 at 3:28 pm
Why you are so afraid of aggregates?
They do not harm people. Honestly.
If there is only 1 value MAX will just present that value and dod not do any aggregation. Exactly as you wish.
But what if there is actually more than one value? Did you think about such scenario?
_____________
Code for TallyGenerator
July 25, 2006 at 3:34 pm
Using this slighty rewritten SP from my article will do the trick for you. It uses no aggregations!
CREATE PROCEDURE uspAirplaneProperties
AS
SET NOCOUNT ON
CREATE TABLE #Aggregates
(
RowText VARCHAR(50),
ColumnText VARCHAR(50),
CellData INT
)
INSERT INTO #Aggregates
(
RowText,
ColumnText,
CellData
)
SELECT Aircraft,
PropertyName,
Value
FROM tblProperties
CREATE UNIQUE INDEX IX_Aggregates ON #Aggregates (RowText, ColumnText, CellData)
CREATE TABLE #Columns
(
ColumnIndex INT IDENTITY (0, 1),
ColumnText VARCHAR(50)
)
INSERT INTO #Columns
(
ColumnText
)
SELECT DISTINCT ColumnText
FROM #Aggregates (INDEX(IX_Aggregates), NOLOCK)
ORDER BY ColumnText
CREATE UNIQUE INDEX IX_Columns ON #Columns (ColumnIndex, ColumnText)
CREATE TABLE #Rows
(
RowText VARCHAR(50)
)
INSERT INTO #Rows
(
RowText
)
SELECT DISTINCT RowText
FROM #Aggregates (INDEX(IX_Aggregates), NOLOCK)
CREATE UNIQUE INDEX IX_Rows ON #Rows (RowText)
DECLARE @ColumnIndex INT,
@MaxColumnIndex INT,
@ColumnText VARCHAR(50),
@SQL VARCHAR(1000)
SELECT @ColumnIndex = 0,
@MaxColumnIndex = MAX(ColumnIndex)
FROM #Columns
WHILE @ColumnIndex <= @MaxColumnIndex
BEGIN
SELECT @ColumnText = ColumnText
FROM #Columns
WHERE ColumnIndex = @ColumnIndex
SELECT @SQL = 'ALTER TABLE #Rows ADD ' + QUOTENAME(@ColumnText) + ' INT NULL'
EXEC (@SQL)
SELECT @SQL = 'UPDATE #Rows SET ' + QUOTENAME(@ColumnText) + ' = #Aggregates.CellData
FROM #Aggregates (INDEX(IX_Aggregates), NOLOCK)
, #Columns (INDEX(IX_Columns), NOLOCK)
WHERE #Rows.RowText = #Aggregates.RowText
AND #Columns.ColumnText = #Aggregates.ColumnText
AND #Columns.ColumnIndex = ' + CAST(@ColumnIndex AS VARCHAR(12))
EXEC (@SQL)
SELECT @ColumnIndex = @ColumnIndex + 1
END
DROP TABLE #Columns
DROP TABLE #Aggregates
SELECT #Rows.*
FROM #Rows
ORDER BY #Rows.RowText
DROP TABLE #Rows
N 56°04'39.16"
E 12°55'05.25"
July 25, 2006 at 3:36 pm
There cannot be duplicate values in the table, or at least there shouldn't be. If I have to use MAX so be it, but calculating the aggregate is an operation that must consume some time even if not much, but it adds up, so I'd prefer to eliminate it if possible.
July 25, 2006 at 3:38 pm
Thanks, Peter, I'll give it a try...but still hoping for a solution re: PIVOT :<.
July 25, 2006 at 3:38 pm
And if you have several tables like tblProperties, just add a UNION after the red text in my previous rewritten SP.
SELECT Aircraft,
PropertyName,
Value
FROM tblProperties
UNION
SELECT Aircraft,
PropertyName,
Value
FROM tblPropertiesAnotherTable
N 56°04'39.16"
E 12°55'05.25"
July 25, 2006 at 3:40 pm
Yes, I know. We all hoped that the new SQL 2005 PIVOT operator really should be a PIVOT, and not just a rewrite for a lot of case statements...
But who knows? Maybe Microsoft will change this behaviour with next service pack? And let PIVOT operator work like the TRANSFORM operator in Access.
N 56°04'39.16"
E 12°55'05.25"
July 25, 2006 at 3:54 pm
Don't forget at the end of the day to compare performance of this solution with performance of simple PIVOT with aggregates.
_____________
Code for TallyGenerator
July 26, 2006 at 6:03 am
FWIW, a number of years ago I picked up a very slim book called Optimizing Transact-SQL: Advanced Programming Techniques. The first chapter deals with single statement SQL solutions to table pivoting and folding problems. Obviously I cannot 'reprint' the text here, and simply describing the code used will not be enough. However, I can attest that the authors' use of characteristic functions in T-SQL yields some elegant yet simple solutions to both pivoting and folding.
Later chapters deal with calculating medians, finding continuous regions in data and computing extreme values.
The ISBN is 0-9649812-0-3. The publisher was SQL Forum Press. The authors are David Rozenshtein, Anatoly Abramovich and Eugene Birger. I do not know if the volume is still in print (try http://www.bookfinder.com) but it is worth searching for.
------------
Buy the ticket, take the ride. -- Hunter S. Thompson
July 26, 2006 at 8:06 am
We will compare performance for the various options. Rozenshtein's book is still available, used and I am purchasing a copy - it sounds like a good book to have, thanks for the info on that.
Viewing 15 posts - 1 through 15 (of 24 total)
You must be logged in to reply to this topic. Login to reply