根据另一列的值按分号将列值拆分为单独的行

Split column value by semicolon into individual rows based on another column's value

我需要根据数量值生成行。

条形码列的值将以分号“;”分隔 我想将每个分隔值变成单独的列。

如果条码值小于数量,则条码栏其他行为空。条码值不会超过数量

| Name         | Quantity    | Barcode
+--------------+-------------+-----------------------------
| Apple        | 5           | barcode1;barcode2;barcode3

预期输出:

| Name         | Barcode
+--------------+----------
| Apple        | barcode1
| Apple        | barcode2
| Apple        | barcode3
| Apple        | 
| Apple        | 

您可以使用下面的代码来获得想要的结果 -

SELECT name, regexp_substr(barcode,'[^;]+',1,level) as barcode
  FROM T
CONNECT BY LEVEL <= quantity;

这里是 fiddle.

您可以使用 CROSS JOIN 拆分字符串,即使在 table 中有多个行,仍然可以获得正确的行数。

WITH
    fruit (name, quantity, barcode)
    AS
        (SELECT 'Apple', 5, 'barcode1;barcode2;barcode3' FROM DUAL
         UNION ALL
         SELECT 'Banana', 4, 'A;B;C' FROM DUAL)
SELECT f.name, s.COLUMN_VALUE AS barcode
  FROM fruit  f
       CROSS JOIN
       TABLE (CAST (MULTISET (    SELECT REGEXP_SUBSTR (f.barcode,
                                                        '[^;]+',
                                                        1,
                                                        LEVEL)
                                    FROM DUAL
                              CONNECT BY LEVEL <= f.quantity) AS SYS.OdciVarchar2List)) s;

如果一次要拆分多个源行,连接方法需要条件来防止交叉匹配;所以你可以这样做:

select name, regexp_substr(barcode, '(.*?)(;|$)', 1, level, null, 1)
from your_table
connect by name = prior name
and prior sys_guid() is not null
and level <= quantity;

由于您使用的是 11g,并且假设是 11gR2,您还可以使用递归 CTE:

with rcte (name, pos, barcode, quantity, all_barcodes) as (
  select name, 1, regexp_substr(barcode, '(.*?)(;|$)', 1, 1, null, 1), quantity, barcode
  from your_table
  union all
  select name, pos + 1, regexp_substr(all_barcodes, '(.*?)(;|$)', 1, pos + 1, null, 1), quantity, all_barcodes
  from rcte
  where pos < quantity
)
select name, barcode
from rcte
order by name, pos;

db<>fiddle