Oracle 中的子字符串查询 SQL
Substring Query in Oracle SQL
我有一个 table,其中有 2 列,格式如下。我想从 Col1
中获取所有字符串,这些字符串从 col2
的单词末尾开始作为单独的列。
例如:如果 Col1
有 ABC:EFG:MNO:XYZ
并且 Col2
有 MNO
,那么输出将有 L1
作为 XYZ
(数据在 Col2
的字符串和 Col1
)
的结尾之间
COL1
COL2
ABC:EFG:MNO:XYZ
MNO
PQR:NOM:XYN:SDF:RST:EDF
NOM
我想要低于输出。
L1
L2
L3
L4
L5
XYZ
XYN
SDF
RST
EDF
我尝试使用子字符串,但它对我不起作用。
此致
按照您的说法,这样的查询就可以完成工作。阅读代码中的注释。
SQL> with
2 test (col1, col2) as
3 -- sample data; you already have that in your table; don't type it
4 (select 'ABC:EFG:MNO:XYZ' , 'MNO' from dual union all
5 select 'PQR:NOM:XYN:SDF:RST:EDF', 'NOM' from dual
6 ),
7 remainder as
8 -- fetch part of COL1 that follows the COL2 value
9 (select col1, col2,
10 substr(col1, instr(col1, col2) + length(col2) + 1) col
11 from test
12 )
13 -- finally, extract up to 5 "words" (as your example suggests) from COL
14 select regexp_substr(col, '\w+', 1, 1) l1,
15 regexp_substr(col, '\w+', 1, 2) l2,
16 regexp_substr(col, '\w+', 1, 3) l3,
17 regexp_substr(col, '\w+', 1, 4) l4,
18 regexp_substr(col, '\w+', 1, 5) l5
19 from remainder;
L1 L2 L3 L4 L5
----- ----- ----- ----- -----
XYZ
XYN SDF RST EDF
SQL>
您可以创建一个存储函数,以便在使用冒号 col1
拆分列 col1
之后通过使用条件聚合动态地转换结果,例如
CREATE OR REPLACE FUNCTION Get_Splitted_Columns RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG('MAX( CASE WHEN rn2 = '''||level||''' THEN col1 END ) AS "L_'||level||'"' , ',' )
WITHIN GROUP ( ORDER BY level )
INTO v_cols
FROM dual
CONNECT BY level <= ( SELECT MAX(REGEXP_COUNT(col1,':',INSTR(col1,col2))) FROM tab );
v_sql :='WITH t AS
(
SELECT REGEXP_SUBSTR(col1,''[^:]+'',1,level) AS col1, col2, level AS rn,
DENSE_RANK() OVER (ORDER BY col1) AS dr
FROM tab
CONNECT BY level <= REGEXP_COUNT(col1,'':'')+1
AND PRIOR SYS_GUID() IS NOT NULL
AND PRIOR col1 = col1
), t2 AS
(
SELECT t.*,MAX(CASE WHEN col1=col2 THEN rn END) OVER (PARTITION BY dr) AS max_rn
FROM t
), t3 AS
(
SELECT dr, max_rn, rn, rn - max_rn AS rn2, col1, col2
FROM t2 tt
WHERE rn > ( SELECT MAX(max_rn) FROM t2 WHERE dr = tt.dr )
)
SELECT '||v_cols||'
FROM t3
GROUP BY dr';
OPEN v_recordset FOR v_sql;
RETURN v_recordset;
END;
/
然后将函数调用为
VAR rc REFCURSOR
EXEC :rc := Get_Splitted_Columns;
PRINT rc
来自SQL开发者的命令行
好吧,如果没有超过 L5 的东西,并且您总是有三个字母,只需使用第一个匹配项的偏移量对其进行硬编码。
WITH tab AS (
SELECT 'ABC:EFG:MNO:XYZ' AS Col1, 'MNO' AS Col2 FROM DUAL
UNION
SELECT 'PQR:NOM:XYN:SDF:RST:EDF' AS Col1, 'NOM' AS Col2 FROM DUAL
)
SELECT tab.Col1,
tab.Col2,
SUBSTR(tab.Col1, NULLIF(INSTR(tab.Col1, tab.Col2), 0) + 4, 3) AS L1,
SUBSTR(tab.Col1, NULLIF(INSTR(tab.Col1, tab.Col2), 0) + 8, 3) AS L2,
SUBSTR(tab.Col1, NULLIF(INSTR(tab.Col1, tab.Col2), 0) + 12, 3) AS L3,
SUBSTR(tab.Col1, NULLIF(INSTR(tab.Col1, tab.Col2), 0) + 16, 3) AS L4,
SUBSTR(tab.Col1, NULLIF(INSTR(tab.Col1, tab.Col2), 0) + 20, 3) AS L5
FROM tab;
您找到与 INSTR 的第一个匹配项,并使用从匹配项 + 条目 * 4 开始的 3 个字符的子字符串。NULLIF 表示没有匹配项。
我有一个 table,其中有 2 列,格式如下。我想从 Col1
中获取所有字符串,这些字符串从 col2
的单词末尾开始作为单独的列。
例如:如果 Col1
有 ABC:EFG:MNO:XYZ
并且 Col2
有 MNO
,那么输出将有 L1
作为 XYZ
(数据在 Col2
的字符串和 Col1
)
COL1 | COL2 |
---|---|
ABC:EFG:MNO:XYZ | MNO |
PQR:NOM:XYN:SDF:RST:EDF | NOM |
我想要低于输出。
L1 | L2 | L3 | L4 | L5 |
---|---|---|---|---|
XYZ | ||||
XYN | SDF | RST | EDF |
我尝试使用子字符串,但它对我不起作用。
此致
按照您的说法,这样的查询就可以完成工作。阅读代码中的注释。
SQL> with
2 test (col1, col2) as
3 -- sample data; you already have that in your table; don't type it
4 (select 'ABC:EFG:MNO:XYZ' , 'MNO' from dual union all
5 select 'PQR:NOM:XYN:SDF:RST:EDF', 'NOM' from dual
6 ),
7 remainder as
8 -- fetch part of COL1 that follows the COL2 value
9 (select col1, col2,
10 substr(col1, instr(col1, col2) + length(col2) + 1) col
11 from test
12 )
13 -- finally, extract up to 5 "words" (as your example suggests) from COL
14 select regexp_substr(col, '\w+', 1, 1) l1,
15 regexp_substr(col, '\w+', 1, 2) l2,
16 regexp_substr(col, '\w+', 1, 3) l3,
17 regexp_substr(col, '\w+', 1, 4) l4,
18 regexp_substr(col, '\w+', 1, 5) l5
19 from remainder;
L1 L2 L3 L4 L5
----- ----- ----- ----- -----
XYZ
XYN SDF RST EDF
SQL>
您可以创建一个存储函数,以便在使用冒号 col1
拆分列 col1
之后通过使用条件聚合动态地转换结果,例如
CREATE OR REPLACE FUNCTION Get_Splitted_Columns RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG('MAX( CASE WHEN rn2 = '''||level||''' THEN col1 END ) AS "L_'||level||'"' , ',' )
WITHIN GROUP ( ORDER BY level )
INTO v_cols
FROM dual
CONNECT BY level <= ( SELECT MAX(REGEXP_COUNT(col1,':',INSTR(col1,col2))) FROM tab );
v_sql :='WITH t AS
(
SELECT REGEXP_SUBSTR(col1,''[^:]+'',1,level) AS col1, col2, level AS rn,
DENSE_RANK() OVER (ORDER BY col1) AS dr
FROM tab
CONNECT BY level <= REGEXP_COUNT(col1,'':'')+1
AND PRIOR SYS_GUID() IS NOT NULL
AND PRIOR col1 = col1
), t2 AS
(
SELECT t.*,MAX(CASE WHEN col1=col2 THEN rn END) OVER (PARTITION BY dr) AS max_rn
FROM t
), t3 AS
(
SELECT dr, max_rn, rn, rn - max_rn AS rn2, col1, col2
FROM t2 tt
WHERE rn > ( SELECT MAX(max_rn) FROM t2 WHERE dr = tt.dr )
)
SELECT '||v_cols||'
FROM t3
GROUP BY dr';
OPEN v_recordset FOR v_sql;
RETURN v_recordset;
END;
/
然后将函数调用为
VAR rc REFCURSOR
EXEC :rc := Get_Splitted_Columns;
PRINT rc
来自SQL开发者的命令行
好吧,如果没有超过 L5 的东西,并且您总是有三个字母,只需使用第一个匹配项的偏移量对其进行硬编码。
WITH tab AS (
SELECT 'ABC:EFG:MNO:XYZ' AS Col1, 'MNO' AS Col2 FROM DUAL
UNION
SELECT 'PQR:NOM:XYN:SDF:RST:EDF' AS Col1, 'NOM' AS Col2 FROM DUAL
)
SELECT tab.Col1,
tab.Col2,
SUBSTR(tab.Col1, NULLIF(INSTR(tab.Col1, tab.Col2), 0) + 4, 3) AS L1,
SUBSTR(tab.Col1, NULLIF(INSTR(tab.Col1, tab.Col2), 0) + 8, 3) AS L2,
SUBSTR(tab.Col1, NULLIF(INSTR(tab.Col1, tab.Col2), 0) + 12, 3) AS L3,
SUBSTR(tab.Col1, NULLIF(INSTR(tab.Col1, tab.Col2), 0) + 16, 3) AS L4,
SUBSTR(tab.Col1, NULLIF(INSTR(tab.Col1, tab.Col2), 0) + 20, 3) AS L5
FROM tab;
您找到与 INSTR 的第一个匹配项,并使用从匹配项 + 条目 * 4 开始的 3 个字符的子字符串。NULLIF 表示没有匹配项。