Необходимо создать n строк на основе значения в столбце

У меня есть следующая таблица

ТАБЛИЦА A

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

Мне нужно

ТАБЛИЦА B

ID | Ref No.
------------
1  | MyRef1
1  | MyRef2
1  | MyRef3
2  | AnotherRef1
2  | AnotherRef2

то есть. Мне нужно создать таблицу B с тем же количеством строк, что и количество в с восходящим номером ref. на каждой строке.

Я могу сделать это с помощью курсоров или UDF, но есть ли более изящное решение?

Ответ 1

Я приду

  1. MyRef и т.д. Является столбцом в таблице A
  2. У вас есть таблица чисел

Что-то вроде:

SELECT * INTO #TableA
FROM
 (
    SELECT  1 AS ID, 3 AS QUANTITY, 'MyRef' AS refColumn
    UNION ALL
    SELECT 2, 2, 'AnotherRef'
) T


;WITH Nbrs ( Number ) AS (
    SELECT 1 UNION ALL
    SELECT 1 + Number FROM Nbrs WHERE Number < 99
)
SELECT
   A.ID, A.refColumn + CAST(N.Number AS varchar(10))
FROM
   #TableA A
   JOIN
   Nbrs N ON N.Number <= A.QUANTITY

Ответ 2

Это создаст количество строк, которое вы хотите, в SQL Server 2005+, хотя я точно не знаю, как вы хотите определить, какие должны быть MyRef и AnotherRef...

WITH
  expanded
AS
(
  SELECT id, Quantity FROM myTable

UNION ALL

  SELECT id, Quantity - 1 FROM expanded WHERE Quantity > 1
)

SELECT
  *,
  ROW_NUMBER() OVER (ORDER BY id, Quantity) AS unique_ref
FROM
  expanded
ORDER BY
  id,
  Quantity

Ответ 3

Ниже приведено правильное количество строк, но мое наблюдение такое же, как @Dems: как вы определяете MyRef и AnotherRef?

Обратите внимание, что для этого требуется, по крайней мере, SQL Server 2005

Заявление SQL

;WITH TableA (ID, Quantity) AS (
    SELECT  1, 3
    UNION ALL SELECT 2, 2
)
, q AS (
    SELECT  ID
            , Number = 1
            , Quantity
    FROM    TableA
    UNION ALL 
    SELECT  ID
            , Number = Number + 1
            , Quantity
    FROM    q
    WHERE   Quantity > Number
)
SELECT  ID
        , CASE WHEN ID = 1 THEN 'MyRef' + CAST(Number AS VARCHAR(1))
               WHEN ID = 2 THEN 'AnotherRef' + CAST(Number AS VARCHAR(1))
          END AS [Ref No.]
FROM    q       
ORDER BY
        ID

Выход

ID  Ref No.
1   MyRef1
1   MyRef2
1   MyRef3
2   AnotherRef1
2   AnotherRef2

Ответ 4

Один выбор для создания строк по столбцу TableA.quantity. Используется только ISO/ANSI SQL Standard синтаксис 2003 (БД должна поддерживать оконную функцию).

Таблица A определение:

|----|----------|---------------|
| 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');

Следующий запрос можно использовать для значения количества до 1000. Для количества до 10000 расширить запрос оператором 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:

|-----------|-------------|---------------|
| 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 |
|-----------|-------------|---------------|

Должно работать на PostgreSQL, Oracle или MSSQL (протестировано на PostgreSQL 9.0)

Отредактировано: оптимизированный запрос с использованием оператора WITH RECURSIVE (идея из 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

Ответ 5

Решение Table Table будет работать в MS Access, если количество записей в tblNumbers превышает максимальное количество значений, найденных в таблице A:

SELECT TableA.ID, TableA.Quantity, tblNumbers.RecNum FROM TableA LEFT JOIN tblNumbers ON tblNumbers.RecNum <= TableA.Quantity ORDER BY TableA.ID, tblNumbers.RecNum;

ПРИМЕЧАНИЕ: tblNumbers.RecNum - это длинное целое число, начиная с строки 1 = 1, строки 2 = 2 и т.д.

Ответ 6

Это также помогло бы. Он использует рекурсию, создает таблицу со строками 1-100.

WITH NBR ( NUM ) AS (
    SELECT 1 UNION ALL
    SELECT 1 + NUM FROM NBR 
    WHERE NUM < 100
)
SELECT * into NUMBERS from NBR