如何根据 Oracle SQL 中的某些条件将列拆分为 2?

How do I split column into 2 based on certain conditions in Oracle SQL?

我有一个 table 的 250k 数据,在这些数据中,我有 1000 行在每个列中都有相同的数据,一个参考列是不同的。

我想做的是在满足一定条件的情况下拆分参考列,如果不满足这些条件,参考值可以保持原样。

以下是我的创建table和插入语句:

CREATE TABLE "BU_TABLE" 
   (   
    "NAME" VARCHAR2(255 BYTE), 
    "TEL_NO" VARCHAR2(255 BYTE), 
    "POST_CODE" VARCHAR2(8 BYTE), 
    "REF_NO" VARCHAR2(255 BYTE)
;

我将 Tel_NoRef_No 列设置为 Varchar2 的原因是因为 spaces 因为数字有 spaces然后a)它会在插入时提示Invalid Number error b)Tel_No目前示例数据没有这个问题但是随着更多数据的添加我可能会遇到这个问题。

插入语句:

Insert into BU_TABLE (NAME,TEL_NO,POST_CODE,REF_NO) values ('Damian','7900123456','ME1 2BC','12345678 1234567891234');
Insert into BU_TABLE (NAME,TEL_NO,POST_CODE,REF_NO) values ('Graeme','7900789012','ME1 2DE','12 345 5678901234567');
Insert into BU_TABLE (NAME,TEL_NO,POST_CODE,REF_NO) values ('Sarah','7900456789','ME1 2FG','90123456 890123456789');

现在我希望 BU_TABLE 保持原样,使用原始数据。我想在这个 table 的后面创建另一个 table 来拆分 Ref_No,所以我有一个 8 个数字的序列,一个 space 然后是 13数字。无论这种模式出现在哪里,我都想复制该行并给我以下内容:

Name   | Tel_No     | Post_Code | Ref_No
Damian | 7900123456 | ME1 2BC   | 12345678
Damian | 7900123456 | ME1 2BC   | 1234567891234

所需代码未找到序列的行,数据行将在 table 中保持不变,所以我的最终 table 将如下所示。这显示了新的数据拆分,其中 Damian 的 2 个参考编号已拆分,现在显示为 2 行,而 Graeme 和 Sarah 有其原始参考编号,因为他们的序列不符合标准。

最终 table:

Name   | Tel_No     | Post_Code | Ref_No
Graeme | 7900789012 | ME1 2DE   | 12 345 5678901234567
Sarah  | 7900456789 | ME1 2FG   | 90123456 890123456789
Damian | 7900123456 | ME1 2BC   | 12345678
Damian | 7900123456 | ME1 2BC   | 1234567891234

希望我的要求在我正在寻找的方面是明确的。

抱歉,还有另一个 post 提出了同样的问题:

但是问题已经结束,因为我被要求添加我的创建和插入语句以使我的要求更清楚,因此我创建了一个新问题。

您可以使用 union all 做您想做的事:

select bu.Name, bu.Tel_No, bu.Post_Code, bu.Ref_No
from bu
where not regexp_like(ref_no, '^[0-9]{8} [0-9]{13}$')
union all
select bu.Name, bu.Tel_No, bu.Post_Code, substr(bu.Ref_No, 1, 8)
from bu
where regexp_like(ref_no, '^[0-9]{8} [0-9]{13}$')
union all
select bu.Name, bu.Tel_No, bu.Post_Code, substr(bu.Ref_No, -13)
from bu
where regexp_like(ref_no, '^[0-9]{8} [0-9]{13}$');

您可以使用 union all 来做到这一点。我在下面展示了一种不同的方法——使用过去常见的逆透视技术(在 Oracle 引入 unpivot 运算符之前)。这将比使用 union all 的解决方案更有效,因为它只需要一次完整的 table 扫描。

我没有显示 table 的创建;我展示了一个 select 语句,您可以使用它来填充新的 table.

select bu.name, bu.tel_no, bu.post_code,
       case when regexp_like(bu.ref_no, '^\d{8} \d{13}$') 
            then
                 case t.c when 1 then substr(bu.ref_no, 1, 8) 
                                 else substr(bu.ref_no, 10)   end
            else bu.ref_no
       end as ref_no
from   bu_table bu join (select 1 as c from dual union all select 2 from dual) t
                   on t.c = 1 or regexp_like(bu.ref_no, '^\d{8} \d{13}$')
;

NAME    TEL_NO      POST_CODE    REF_NO
------  ----------  ---------  -----------------------
Damian  7900123456  ME1 2BC    12345678
Graeme  7900789012  ME1 2DE    12 345 5678901234567
Sarah   7900456789  ME1 2FG    90123456 890123456789
Damian  7900123456  ME1 2BC    1234567891234

您可以使用以下查询:

SQL> SELECT NAME, TEL_NO, POST_CODE,
  2          CASE
  3              WHEN CNT = 1 THEN REF_NO
  4              ELSE CASE
  5                  WHEN L = 1 THEN SUBSTR(REF_NO, 1, 8)
  6                  ELSE SUBSTR(REF_NO, 10)
  7              END
  8          END AS REF_NO
  9  FROM
 10      (SELECT T.*,
 11              CASE
 12                  WHEN REGEXP_LIKE ( REF_NO,
 13                                     '^[0-9]{8} [0-9]{13}$' ) THEN 2
 14                  ELSE 1
 15              END AS CNT
 16         FROM BU_TABLE T ) MT
 17      JOIN (SELECT LEVEL AS L
 18              FROM DUAL CONNECT BY LEVEL <= 2
 19      ) ON ( CNT >= L );

NAME       TEL_NO       POST_COD REF_NO
---------- ------------ -------- ------------------------
Damian     7900123456   ME1 2BC  12345678
Graeme     7900789012   ME1 2DE  12 345 5678901234567
Sarah      7900456789   ME1 2FG  90123456 890123456789
Damian     7900123456   ME1 2BC  1234567891234

SQL>

干杯!!