Convert Rows into Columns

  • zerbit (7/18/2014)


    I dislike the solution proposed, it's far too complicated to reach a so easy task.

    You requirement was to print 3 lots at a time per line of document. This mean that you should have a table with lot associated with the Line, a simple left join will suffice.

    Surely the population of this table must be dynamic and should be included in your "simpler" solution? Suppose only a subset of the lot numbers need to be printed. Then there will be gaps, .e.g.

    C

    D F

    G H I

    J K

    M N O

  • Unfortunately no, but what I have discovered is it can be done without cursors. Pseudo code is use a select to build your create Table statement, then an Insert to insert your primary keys, then an Update to stick the values into the rows.

    Random numbers of columns is not easy to do in T-SQL.

    But if you know the number of columns- Pivot/Unpivot is easier than the above approach.

    Ted Seeber
    I find your secrets in your data.
    http://www.informaitonr.us

  • You could add a category column and pivot

    with cte

    as

    (

    select LotNo

    , ( row_number() over ( order by LotNo ) + 2 ) % 3 as Remainder

    , ( row_number() over ( order by LotNo ) - 1) / 3 as Category

    from lotno

    )

    select Category, [0] as column1, [1] as column2, [2] as column3

    from cte

    pivot

    (

    min(LotNo) for Remainder in ([0],[1],[2])

    ) as piv

    Returns

    Categorycolumn1column2column3

    0ABC

    1DEF

    2GHI

    3JKL

    4MNO

    5PQR

    6STU

    7VWX

    8YZNULL

  • Anyone remember Steve Dassin and his set of stored procedure and functions call RAC? It handled all of these crosstab and hierarchy questions. You pass in the base info and it created the correctly built crosstab every time. I bought it back in 2000 and still use it today on SQL 2012, I'd suggest if you can find him grab this up, it's simple and flat works.

    http://forums.databasejournal.com/showthread.php?9932-Crosstab-pivoting-utility-for-sql-server-2000

    Chuck

  • elghazal.med (12/11/2015)


    Hello,

    I already worked on this. But i used another tool which is Stata to convert both column to rows and rows to column and i used TOS to insert Data in DB. It is great and easy.

    It also adds to the proverbial "Tower of Babel". Why would you use an external 3rd Party tool to do something that's so simple to do where the data is actually stored at?

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • johnbrown105 56149 (12/11/2015)


    zerbit (7/18/2014)


    I dislike the solution proposed, it's far too complicated to reach a so easy task.

    You requirement was to print 3 lots at a time per line of document. This mean that you should have a table with lot associated with the Line, a simple left join will suffice.

    Surely the population of this table must be dynamic and should be included in your "simpler" solution? Suppose only a subset of the lot numbers need to be printed. Then there will be gaps, .e.g.

    C

    D F

    G H I

    J K

    M N O

    You would simply apply the filter that defines the subset where the rows are numbered and then you won't have that problem.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • fregatepllada (7/17/2014)


    Thanks Jeff - I did CROSSTAB implementation before SQL 2005.

    For my current project I stick with PIVOT (I have less than 10K rows). 😉

    Heh... I love it when people justify slower code based on lower rowcounts and then scream bloody murder when they need to do something similar with much larger row counts. Get used to doing it the fastest way possible all the time and then you'll only need to remember one way. NEVER justify slow or resource intensive code based on low row counts because you can't guarantee that no one will use your code for something bigger. In most cases, you usually can't even guarantee that the tables that you currently know to be small will never grow.

    It takes so little time to do it right. Do it right all the time. No excuses. If you do it right all the time, you'll also get much faster at it.;-)

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • [p]

    This seems like an interesting case for a PIVOT example as a way top promote thinking in a more relational sense. Of course, this makes the assumption that one is using a version providing PIVOT.

    [/p]

    [p]

    Forgive the omission of the table set up -- and my use of temp tables instead or real ones. The original data table is exactly like the table used in article's example.

    [/p]

    CREATE TABLE #ColumnNames (ColumnKey int, Columnname VARCHAR(10))

    DELETE #ColumnNames

    INSERT INTO #ColumnNames (ColumnKey, ColumnName)

    Values (0, 'Column1')

    , (1, 'Column2')

    , (2, 'Column3')

    SELECT max(column1) Lot1, max(column2) Lot2, max(column3) Lot3 FROM (

    SELECT Source.LotNo, source.ColumnKey, Source.RowKey, map.Columnname FROM (

    SELECT LotNo

    , (Row_Number() over (order by LotNo) + 2) / 3 as RowKey

    , (Row_Number() over (order by LotNo) - 1) % 3 as ColumnKey

    FROM #OriginalResultSet

    ) Source

    INNER JOIN #ColumnNames Map on Map.ColumnKey = Source.ColumnKey %3

    ) AS ResultSet

    PIVOT (

    MAX (LotNo) FOR ColumnName in (Column1, Column2, Column3)

    ) as it

    group by RowKey

  • vjonnal1 (7/17/2014)


    I am bit confused here, what's preventing you to use PIVOT function here?

    Performance.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • fregatepllada (7/17/2014)


    Luis, if we talking about performance difference did you try to benchmark your approach vs PIVOT?

    IFAIK PIVOT became part of built-in SQL Server functionality since SQL Server 2005. 😉

    Not all that is "new" is better. PIVOT is slower than a CROSSTAB. Since no one that's asking this question or posting PIVOT code actually appear to have read the article I provided a link to about how CROSS TAB beats PIVOT, I'm setting up a larger test that will include all posted code that works to demonstrate why you should consider NOT using PIVOT. Then they can finally go back and read the article I provided a link to and see what some of the other advantages of CROSSTAB are.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • fregatepllada (7/17/2014)


    Thanks Luis, I hate to bring another dimension to performance test but I am using TABLE variable, not temporary table. 😉

    Where's that code? I'll add it to the test I'm setting up...

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • zerbit (7/18/2014)


    I dislike the solution proposed, it's far too complicated to reach a so easy task.

    You requirement was to print 3 lots at a time per line of document. This mean that you should have a table with lot associated with the Line, a simple left join will suffice.

    If your table looks like this

    IDNoLotNoSaleOrdLine

    1A1

    2B1

    3C1

    4D2

    5E2

    6F2

    7G2

    8H2

    9I2

    10J2

    11K3

    12L3

    13M3

    14N3

    15O3

    16P3

    17Q3

    18R3

    19S3

    20T3

    21U3

    22V3

    23W3

    24X3

    25Y3

    26Z3

    select L1.SaleOrdLine,L1.LotNo as L1,coalesce(L2.LotNo,'') as L2,coalesce(L3.LotNo,'') as L3

    from [LotNo] L1

    left join [LotNo] L2 on L1.saleOrdLine=L2.SaleOrdLine and L2.idno=L1.IDNo+1

    left join [LotNo] L3 on L2.saleOrdLine=L3.SaleOrdLine and L3.idno=L2.IDNo+1

    where L1.IDNo%3=1

    with this results:

    SaleOrdLineL1L2L3

    1ABC

    2DEF

    2GHI

    2J

    3MNO

    3PQR

    3STU

    3VWX

    3YZ

    Best regards,

    PS: your solution is indeed good, but for more complex applications.

    You say the other solution is too complex but where is YOUR code to create the SaleOrdLine column? And do you really think that 3 scans of a table will be faster? If so (and I know you might not be around after a year), post the code to update the SaleOrdLine column and I'll be happy to include it in the test I'm building. As they say, "one test is worth a thousand expert opinions". 😉

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • steven.bingham (7/18/2014)


    You're usage of row_number(), modulo and such is impressive, but I

    must admit that I found the solution a bit over complex and it was making

    my head hurt a bit.

    Consider the following code, the key is using the COALESCE statement, the

    example assumes using the original 'LOTNO' table populated in the post:

    DECLARE @returnResult varchar(255)

    , @StartLotNumber int = 0

    , @LastLotNumber int = 13

    SELECT @returnResult = COALESCE(@returnResult + ',', '') + lot.LotNo, @LastLotNumber = IDNo

    FROM dbo.LotNo lot

    WHERE IDNo BETWEEN @StartLotNumber AND @LastLotNumber

    SELECT 'Lots for Line Item#1: ' + @returnResult

    select @StartLotNumber = @LastLotNumber + 1, @LastLotNumber = @StartLotNumber + 13, @returnResult = ''

    SELECT @returnResult = COALESCE(@returnResult + ',', '') + lot.LotNo, @LastLotNumber = IDNo

    FROM dbo.LotNo lot

    WHERE IDNo BETWEEN @StartLotNumber AND @LastLotNumber

    SELECT 'Lots for Line Item#2: ' + @returnResult

    OUTPUT RESULTS

    Lots for Line Item#1: A,B,C,D,E,F,G,H,I,J,K,L,M

    Lots for Line Item#2: ,N,O,P,Q,R,S,T,U,V,W,X,Y,Z

    But that doesn't create the same output. You're just concatenating data and if the data isn't all the same length, it'll be a mess besides. I'm not including this in the test because it doesn't meet the objective in the article.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • seebert42 (12/11/2015)


    Unfortunately no, but what I have discovered is it can be done without cursors. Pseudo code is use a select to build your create Table statement, then an Insert to insert your primary keys, then an Update to stick the values into the rows.

    Random numbers of columns is not easy to do in T-SQL.

    But if you know the number of columns- Pivot/Unpivot is easier than the above approach.

    I'll have to respectfully disagree on all counts but, even if it was, PIVOT is slower than CROSSTAB.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Columnar output that is row-ordered is difficult to read, so I worked on a variation of the requirement - column-order sorting, with a flexible number of columns. In the code below, the number of cols can be set anywhere from 1 to 6. I've split the code into multiple stages of CTEs because my TSQL-foo is weak. I am sure there are better solutions. (I renamed the table to "Lot" to avoid the confusion of "LotNo" being the name of both table and column).

    If you have four columns, my target results would be:

    AHOV

    BIPW

    CJQX

    DKRY

    ELSZ

    FMT

    GNU

    declare @NumCols int = 4

    declare @NumRows int

    select @NumRows = (COUNT(*)+(@NumCols-1))/@NumCols from lot;

    raiserror( '@NumRows=%i',0,0,@NumRows)

    ;

    with Data1 as

    (

    SELECT LotNo, ROW_NUMBER() OVER(ORDER BY LotNo) AS RowNum

    from Lot

    ),

    Data2 as

    (

    select LotNo, RowNum, (RowNum+@NumRows-1)/@NumRows as ColNum

    FROM Data1

    ),

    Data3 as

    (

    select LotNo, RowNum, Colnum, ROW_NUMBER() OVER(PARTITION BY Colnum ORDER BY RowNum) AS ColRow

    FROM Data2

    ),

    Data4 as

    (

    select LotNo, RowNum, ColNum, ColRow, (ColRow-1)*@NumCols+ColNum as SortNum from data3

    )

    SELECT

    MAX(CASE WHEN (@NumCols > 0) and (SortNum % @NumCols = 0) THEN LotNo ELSE '' END) AS [Col1],

    MAX(CASE WHEN (@NumCols > 1) and (SortNum % @NumCols = 1) THEN LotNo ELSE '' END) AS [Col2],

    MAX(CASE WHEN (@NumCols > 2) and (SortNum % @NumCols = 2) THEN LotNo ELSE '' END) AS [Col3],

    MAX(CASE WHEN (@NumCols > 3) and (SortNum % @NumCols = 3) THEN LotNo ELSE '' END) AS [Col4],

    MAX(CASE WHEN (@NumCols > 4) and (SortNum % @NumCols = 4) THEN LotNo ELSE '' END) AS [Col5],

    MAX(CASE WHEN (@NumCols > 5) and (SortNum % @NumCols = 5) THEN LotNo ELSE '' END) AS [Col6]

    FROM (

    -- add row number to base data. Start at 3 so that first value % 3 = 0 (column 1)

    (SELECT top 1000 LotNo, ColRow, SortNum-1 as SortNum FROM Data4 order by SortNum)

    ) AS derived

    GROUP BY ColRow

    If I set numer of columns 6 , I get

    AFKPUZ

    BGLQV

    CHMRW

    DINSX

    EJOTY

Viewing 15 posts - 31 through 45 (of 58 total)

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