2

I have worked out how to pivot a row from a table using PIVOT in SQL Server 2005, however, I dont like the method as I have had to hard code the columns (Currency Codes) and I would like to have the Pivot select the columns dynamically.

As an Example, imagine you have the following table (called OrderCash):

OrderID   CAD     CHF     EUR     GBP     JPY     NOK     USD
40        0       0       128.6   552.25  -9232   0       -4762
41        0       0       250.2   552.25  -9232   0       -4762
42        233.23  0       552.25  -9232   0       0       -4762

The hard-coded Pivot statement is:

SELECT  OrderID,
        CurrCode + 'GBP CURNCY' AS Ticker,
        Cash AS Position
FROM
(
    SELECT OrderID,
        CAD,
        CHF,
        EUR,
        GBP,
        JPY,
        NOK,
        USD
    FROM OrderCash
) p
UNPIVOT
(
    Cash FOR CurrCode IN 
    (CAD, CHF, EUR, GBP, JPY, NOK, USD)
) AS unpvt
WHERE Cash != 0
And OrderID = 42

This would return the following required table:

OrderID   Ticker           Position
42        CADGBP CURNCY    233.23
42        EURGBP CURNCY    552.25
42        GBPGBP CURNCY    -9232
42        USDGBP CURNCY    -4762

The problem arrises further down the road when someone tells me I need to have AUD as a new currency in the table?

FYI, I have a table-valued function that returns all the column names as a table:

ALTER FUNCTION [dbo].[GetTableColumnNames]
        (
        @TableName NVARCHAR(250),
        @StartFromColumnNum INT
        )

    RETURNS @ReturnTable TABLE
        (
        ColName NVARCHAR(250)
        )
AS

BEGIN
    INSERT INTO @ReturnTable
        SELECT COLUMN_NAME from information_schema.columns
        WHERE TABLE_NAME = @TableName
            AND ORDINAL_POSITION >= @StartFromColumnNum
        ORDER BY ORDINAL_POSITION

    RETURN
END 

So the easy bit has been done (SELECT * FROM dbo.GetTableColumnNames('OrderCash',2)), the problem I am having is inserting this 'dynamic' table with the column names into the Pivot?

Any help would be much appreciated. Many thanks Bertie.

Bertie
  • 1,163
  • 3
  • 14
  • 26
  • 1
    I'll toss out the (typical & irritating) pragmatist response: when dealing with exchange rates and foreign currencies, you are probabaly much, much better off normalizing your data. It seems more that likely that someone will always want "just one more currency" added to you list. – Philip Kelley Sep 26 '11 at 13:49

1 Answers1

3

I've done a few too many of these dynamic queries of late... (my columns shift by client by month). Here's one way to do it--no testing, no debugging, there might be a few bugs to iron out:

DECLARE
  @Command     nvarchar(max)
 ,@ColumnList  nvarchar(max)
 ,@OrderId     int
 ,@Debug       bit


--  Build a comman-delimited list of the columns
SELECT @ColumnList = isnull(@ColumnLIst + ',', , '') + ColName
 from dbo.GetTableColumnNames('OrderCash', 2)


--  Insert the list of columns in two places in your query
SET @Command = replace('
SELECT  OrderID, 
        CurrCode + ‘‘GBP CURNCY’‘ AS Ticker, 
        Cash AS Position 
FROM 
( 
    SELECT OrderID, <@ColumnList>
    FROM OrderCash 
) p 
UNPIVOT 
( 
    Cash FOR CurrCode IN  
    (<@ColumnList>) 
) AS unpvt 
WHERE Cash != 0 
And OrderID = @OrderId
', '<@ColumnList>', @ColumnList)


--  Always include something like this!
IF @Debug = 1
    PRINT @Command

--  Using sp_executeSQL over EXECUTE (@Command) allows you execution
--  plan resuse with parameter passing (this is the part you may need
--  to debug on a bit, but it will work)
EXECUTE sp_executeSQL @Command, N'@OrderId int', @OrderId
Philip Kelley
  • 39,426
  • 11
  • 57
  • 92
  • 1
    +1, Very nice answer, I was about to answer something similar, but yours is a lot more parameterized. I would only add a link to your answer: http://www.sommarskog.se/dynamic_sql.html – Lamak Sep 26 '11 at 14:02
  • Yep, he's a key for serious understanding of dynamic SQL. – Philip Kelley Sep 26 '11 at 14:11