Need to generate n rows based on a value in a column

后端 未结 6 868
闹比i
闹比i 2020-12-15 06:41

I have the following table

TABLE A

ID | QUANTITY
------------
1  | 3
2  | 2

What I need is

TABLE B

ID | Ref          


        
6条回答
  •  情话喂你
    2020-12-15 07:33

    Single select to generate rows by column TableA.quantity. Used only ISO/ANSI SQL Standard syntax 2003 (DB must support window function).

    TableA definition:

    |----|----------|---------------|
    | id | quantity | another_value |
    |----|----------|---------------|
    |  1 |         3|       value_a |
    |  2 |         2|       value_b |
    |  3 |         6|       value_c |
    |----|----------|---------------|
    
    CREATE TABLE TableA AS
      (SELECT 1 as ID, 3 AS quantity, 'value_a' AS another_value 
      UNION SELECT 2, 2, 'value_b' 
      UNION SELECT 3, 6, 'value_c');
    

    The following query can be used for quantity value up to 1000. For quantity up to 10000 extend query by statement CROSS JOIN ten AS rank10000...

    SELECT 
      ROW_NUMBER() OVER(order by id) as unique_id, 
      id as original_id, 
      another_value || ROW_NUMBER() OVER (PARTITION BY id) as another_value
    FROM TableA
    INNER JOIN
      (SELECT row_number() OVER () AS rnum FROM
        (WITH ten AS (SELECT 1 AS id UNION SELECT 2 
             UNION SELECT 3 UNION SELECT 4 
             UNION SELECT 5 UNION SELECT 6 
             UNION SELECT 7 UNION SELECT 8 
             UNION SELECT 9 UNION SELECT 10)
         SELECT * 
         FROM ten AS rank10 
         CROSS JOIN ten AS rank100 
         CROSS JOIN ten AS rank1000
        ) helper
      ) help ON help.rnum <= TableA.quantity
    

    SQL Result:

    |-----------|-------------|---------------|
    | unique_id | original_id | another_value |
    |-----------|-------------|---------------|
    |         1 |           1 |      value_a1 |
    |         2 |           1 |      value_a2 |
    |         3 |           1 |      value_a3 |
    |         4 |           2 |      value_b1 |
    |         5 |           2 |      value_b2 |
    |         6 |           3 |      value_c1 |
    |         7 |           3 |      value_c2 |
    |         8 |           3 |      value_c3 |
    |         9 |           3 |      value_c4 |
    |        10 |           3 |      value_c5 |
    |        11 |           3 |      value_c6 |
    |-----------|-------------|---------------|
    

    It should be work on PostgreSQL, Oracle or MSSQL (tested on PostgreSQL 9.0)

    Edited: Optimized query using statement WITH RECURSIVE (idea from MatBailie):

    SELECT 
      ROW_NUMBER() OVER() as unique_id, 
      id as original_id, 
      another_value || ROW_NUMBER() OVER (PARTITION BY id) as another_value
    FROM 
      (WITH RECURSIVE helper AS 
        (SELECT id, quantity, another_value FROM TableA 
         UNION ALL 
         SELECT id, quantity-1, another_value FROM helper WHERE quantity > 1
        ) SELECT * FROM helper ORDER BY id, quantity
      ) TableB
    

提交回复
热议问题