如何根据 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_No
和 Ref_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>
干杯!!
我有一个 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_No
和 Ref_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>
干杯!!