Skip to content
Advertisement

Five Columns to a single row

I have the following data

+--------+
| orders |
+--------+
| S1     |
| S2     |
| S3     |
| S4     |
| S5     |
| S6     |
| S7     |
| S8     |
| S9     |
| S10    |
| S11    |
| S12    |
+--------+

I am required to return the result as follows – fit five rows in one column:

+-----------------+
|     Orders      |
+-----------------+
| S1,S2,S3,S4,S5  |
| S6,S7,S8,S9,S10 |
| S11,S12         |
+-----------------+

There is nothing to group on or segregate these into rows. So I assigned a row_number and did mod 5 on the row_number. It almost works, but not quite.

Here is what I have tried:

;with mycte as (
select
'S1' as orders
union all select
'S2'
union all select
'S3'
union all select
'S4'
union all select
'S5'
union all select
'S6'
union all select
'S7'
union all select
'S8'
union all select
'S9'
union all select
'S10'
union all select
'S11'
union all select
'S12'
)
,mycte2 as (
Select 
orders
,ROW_NUMBER() over( order by orders) %5 as rownum 
from mycte
)
select distinct
 STUFF((
            SELECT ',' + mycte2.orders
            FROM mycte2
            where t1.rownum= mycte2.rownum
            FOR XML PATH('')
            ), 1, 1, '') orders 
, rownum
 from mycte2 t1

the result is :

+-----------+--------+
|  orders   | rownum |
+-----------+--------+
| S1,S3,S8  |      1 |
| S10,S4,S9 |      2 |
| S11,S5    |      3 |
| S12,S6    |      4 |
| S2,S7     |      0 |
+-----------+--------+

Can someone please show me how to get to my desired result?

Advertisement

Answer

How about

CREATE TABLE T
    ([orders] varchar(3));

INSERT INTO T
    ([orders])
VALUES
    ('S1'),
    ('S2'),
    ('S3'),
    ('S4'),
    ('S5'),
    ('S6'),
    ('S7'),
    ('S8'),
    ('S9'),
    ('S10'),
    ('S11'),
    ('S12');

WITH CTE AS
(
  SELECT Orders,
        (ROW_NUMBER() OVER(ORDER BY LEN(Orders)) - 1) / 5 RN
  FROM T
)
SELECT STRING_AGG(Orders, ',')
FROM CTE
GROUP BY RN
ORDER BY RN;

OR

SELECT STUFF(
              (
                SELECT ',' + Orders
                FROM CTE
                WHERE RN = TT.RN
                FOR XML PATH('')
              ), 1, 1, ''
            ) Orders
FROM CTE TT
GROUP BY RN
ORDER BY RN;

You can use (SELECT 1) instead of LEN(Orders)

Returns:

+-----------------+
|     Orders      |
+-----------------+
| S1,S2,S3,S4,S5  |
| S6,S7,S8,S9,S10 |
| S11,S12         |
+-----------------+

Demo

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement