Mental block with unpivot

  • Hi, I have the following query:

    select

    @drawdrownPct AS largestDrawDownPct

    ,avg(pctAccountChange) as avgPctAccountChange

    ,max(pctAccountChange) as maxPctAccountChange

    ,min(pctAccountChange) as minPctAccountChange

    ,AVG (case when b.pctAccountChange > 0.1 then pctAccountChange end) as avgPctAccountChangeWinners

    ,AVG (case when b.pctAccountChange < -0.1 then pctAccountChange end) as avgPctAccountChangeLosers

    from

    #BaseTradeStats b

    This query returns one row. I would like a query that produces two columns: pctChangeDescription, pctAccountChange which is effectively an unpivot. How would I write this - should I use the UNPIVOT statement? I'm not sure how to write this.

  • Keymoo,

    It'll be very difficult to show you usable code without having some sample DDL and data, as well as a sample of the desired result. Check the first link in my sig for this.

    However, for the unpivot, I don't think that's what you want.

    When you unpivot, you'd basically take four columns of repeating data and turn them into two columns. IE: ID, pct1, pct2, pct3, and pct4. This would turn into a 3 column set of ID, PctName, pctValue, with pct1/2/3/4 as the PctName, and the value originally in those columns in pctValue.

    Definately need samples to help you out here, but from your sample code, you don't want unpivot.


    - Craig Farrell

    Never stop learning, even if it hurts. Ego bruises are practically mandatory as you learn unless you've never risked enough to make a mistake.

    For better assistance in answering your questions[/url] | Forum Netiquette
    For index/tuning help, follow these directions.[/url] |Tally Tables[/url]

    Twitter: @AnyWayDBA

  • Sorry for the tardiness - here's some sample data and the actual query I am running:

    set nocount on

    CREATE TABLE #BaseTradeStats(

    [tradeId] [int] NOT NULL,

    [minOrderDateTime] datetime,

    [symbol] [char](6) NOT NULL,

    [pctAccountChange] [decimal](38, 6) NULL,

    CONSTRAINT [PK_BaseTradeStats] PRIMARY KEY NONCLUSTERED

    (

    [tradeId] ASC

    )

    )

    CREATE CLUSTERED INDEX [basetradestats_cidx] ON #BaseTradeStats

    (

    [symbol]

    )

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(116,'Jan 6 2010 3:00:00:000AM','AUDJPY',0.688740)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(99,'Jan 6 2010 7:00:00:000AM','CADJPY',0.509932)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(161,'Jan 21 2010 3:00:00:000PM','CHFJPY',0.885134)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(174,'Jan 6 2010 3:00:00:000PM','EURCHF',-0.179938)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(126,'Jan 14 2010 11:00:00:000AM','EURGBP',0.745437)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(127,'Jan 27 2010 7:00:00:000AM','EURGBP',0.321225)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(63,'Jan 6 2010 3:00:00:000PM','EURJPY',-0.283782)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(64,'Jan 14 2010 3:00:00:000AM','EURJPY',-0.356655)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(65,'Jan 19 2010 3:00:00:000AM','EURJPY',0.893750)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(1,'Jan 19 2010 11:00:00:000AM','EURUSD',1.375000)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(78,'Jan 4 2010 7:00:00:000PM','GBPCHF',1.152172)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(79,'Jan 18 2010 3:00:00:000AM','GBPCHF',1.159340)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(80,'Jan 27 2010 11:00:00:000AM','GBPCHF',0.048542)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(139,'Jan 8 2010 7:00:00:000AM','GBPJPY',-0.391604)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(140,'Jan 26 2010 7:00:00:000AM','GBPJPY',0.282684)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(17,'Jan 7 2010 11:00:00:000AM','GBPUSD',-1.910000)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(18,'Jan 18 2010 3:00:00:000AM','GBPUSD',0.275862)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(150,'Jan 13 2010 11:00:00:000AM','USDCHF',-0.404151)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(152,'Jan 26 2010 3:00:00:000AM','USDCHF',0.454544)

    INSERT INTO [#BaseTradeStats] ([tradeId],[minOrderDateTime],[symbol],[pctAccountChange])VALUES(39,'Jan 27 2010 3:00:00:000AM','USDJPY',-0.987500)

    -- work out the compound percentage account increase for the set

    declare

    @compoundChange decimal (38,6),

    @accountGrowth decimal (10,1)

    ;

    -- calculate the largest drawdown for the trade series

    select row_number() over (order by minOrderDateTime) as Row_Order

    , minOrderDateTime, sum(pctaccountchange) as net_pctChange

    into #grouped_Performance

    from #BaseTradeStats b

    group by minOrderDateTime

    create clustered index ix_row_order on #grouped_Performance(Row_Order)

    alter table #grouped_Performance

    add Running_Sum decimal(38,6)

    DECLARE

    @runningValue [DECIMAL](38, 6), -- to hold the intermediate values

    @Sequence INT -- verify that the Sequence of processing is the same as the reqired Sequence

    SET @Sequence=0

    SET @runningValue=1000

    ;

    WITH SafeTable AS

    (

    SELECT net_pctChange

    , Row_Order AS Sequence -- define the sequence for data processing

    , Running_Sum

    FROM #grouped_Performance

    )

    UPDATE SafeTable

    SET

    @Sequence = CASE WHEN Sequence = @Sequence + 1 THEN Sequence ELSE 1/0 END, -- double check to be still in sync

    @runningValue = (@runningValue*(1+net_pctChange/100)), -- calculate the new value

    Running_Sum = @runningValue -- store the value in the requested format

    FROM SafeTable

    WITH (TABLOCKX) -- IMPORTANT: lock the table to avoid data changes in between

    OPTION (MAXDOP 1); -- avoid parallel processing to ensure proper sequence

    declare

    @drawdrownPct decimal(5,2)

    ;with cte as (

    select gpa.minOrderDateTime as drawdownPeakDateTime

    , gpb.minOrderDateTime as drawdownTroughDateTime

    , (gpa.Running_Sum - gpb.Running_Sum) / gpa.Running_Sum * 100 as pct_drop

    from #grouped_Performance gpa

    join #grouped_Performance gpb

    on gpa.Row_Order < gpb.Row_Order

    and gpa.Running_Sum > gpb.Running_Sum

    )

    select top 1

    @drawdrownPct = pct_drop * -1

    from cte

    order by pct_drop desc

    option (maxrecursion 10000);

    -- I need help with this bit so that the results are returned as two columns unpivoted

    select

    @drawdrownPct AS largestDrawDownPct

    ,avg(pctAccountChange) as avgPctAccountChange

    ,max(pctAccountChange) as maxPctAccountChange

    ,min(pctAccountChange) as minPctAccountChange

    ,AVG (case when b.pctAccountChange > 0.1 then pctAccountChange end) as avgPctAccountChangeWinners

    ,AVG (case when b.pctAccountChange < -0.1 then pctAccountChange end) as avgPctAccountChangeLosers

    from

    #BaseTradeStats b

    drop table #grouped_Performance

    drop table #BaseTradeStats

  • Keymoo,

    I scanned through your code twice, and nowhere can I find anything that seems like it would translate to your pctDescription column. Am I missing something here, or does it not exist yet in any capacity?


    - Craig Farrell

    Never stop learning, even if it hurts. Ego bruises are practically mandatory as you learn unless you've never risked enough to make a mistake.

    For better assistance in answering your questions[/url] | Forum Netiquette
    For index/tuning help, follow these directions.[/url] |Tally Tables[/url]

    Twitter: @AnyWayDBA

  • Hi Craig,

    I basically need to transpose columns to rows. So instead of the results looking like this:

    largestDrawDownPct avgPctAccountChange maxPctAccountChange minPctAccountChange avgPctAccountChangeWinners avgPctAccountChangeLosers

    ------------------ ------------------- ------------------- ------------------- -------------------------- -------------------------

    -3.49 0.213936 1.375000 -1.910000 0.728651 -0.644804

    I want the results to look like this:

    description pctAccountChange

    --------------------------- ----------------

    largestDrawDownPct -3.49

    avgPctAccountChange 0.213936

    maxPctAccountChange 1.375000

    minPctAccountChange -1.910000

    avgPctAccountChangeWinners 0.728651

    avgPctAccountChangeLosers -0.644804

  • keymoo (1/18/2011)


    I want the results to look like this:

    description pctAccountChange

    --------------------------- ----------------

    largestDrawDownPct -3.49

    avgPctAccountChange 0.213936

    maxPctAccountChange 1.375000

    minPctAccountChange -1.910000

    avgPctAccountChangeWinners 0.728651

    avgPctAccountChangeLosers -0.644804

    *facepalms* I'm sorry, I got lost in translation. You're absolutely right, you want unpivot.

    WITH cte1 AS

    (SELECT

    CONVERT( DECIMAL(19,6), -3.49) AS largestDrawDownPct,

    CONVERT( DECIMAL(19,6), 0.213936 ) AS avgPctAccountChange,

    CONVERT( DECIMAL(19,6), 1.375000 ) AS maxPctAccountChange,

    CONVERT( DECIMAL(19,6), -1.91000 ) AS minPctAccountChange,

    CONVERT( DECIMAL(19,6), 0.728651 ) AS avgPctAccountChangeWinners,

    CONVERT( DECIMAL(19,6), -0.644804 ) AS avgPctAccountChangeLosers

    )

    select

    [Description],

    pctAccountChange

    from

    cte1

    UNPIVOT ( pctAccountChange FOR [Description]

    IN (largestDrawDownPct, avgPctAccountChange, maxPctAccountChange,

    minPctAccountChange, avgPctAccountChangeWinners, avgPctAccountChangeLosers)

    ) AS unpvt

    Note, you'll want to make sure you do the convert decimal on the result sets to make sure they're the same type, or the UNPIVOT tends to get cranky.


    - Craig Farrell

    Never stop learning, even if it hurts. Ego bruises are practically mandatory as you learn unless you've never risked enough to make a mistake.

    For better assistance in answering your questions[/url] | Forum Netiquette
    For index/tuning help, follow these directions.[/url] |Tally Tables[/url]

    Twitter: @AnyWayDBA

Viewing 6 posts - 1 through 5 (of 5 total)

You must be logged in to reply to this topic. Login to reply