Oracle SQL 查询基于字符串模式检索父记录
Oracle SQL query to retrieve parent records based on a string pattern
环境:Oracle 12c
我在 table 中有以下数据集,称为:MY_INFO
ID NAME INFO
--------- --------- -----------
1 Isle 4 L 4
2 Isle 0 L 5/0
3 Isle 2 L 6/0/2
4 Isle 2 L 4/2
5 Isle 0 L 4/0
6 Isle 0 L 5/0
7 Isle 2 L 7/0/2
8 Isle 3 L 8/3
9 Isle 2 L 6/0/2
10 Isle 2 L 4/0/2
11 Isle 10 L 10
12 Isle 0 L 11/0
13 Isle 2 L 11/0/2
鉴于此 MY_INFO
table 中的上述记录并假设我使用的记录 ID:10,即:
ID NAME INFO
--------- --------- -----------
10 Isle 2 L 4/0/2
就像层次结构一样,我需要一种方法来检索遵循以下模式的所有记录,至少对于这条记录。
虽然在这种情况下,我只需要检索以下三个匹配的记录,相反,即
4
4/0
4/0/2
所以使用 INFO 值:L 4/0/2
,我现在需要分支到 L 4/0
并检索该记录,然后一直回到顶级记录 L 4
所以最后,我希望检索的记录是:
ID NAME INFO
--------- --------- -----------
1 Isle 4 L 4
5 Isle 0 L 4/0
10 Isle 2 L 4/0/2
不确定如何使用 SQL 解决此问题。
这里有一个方法...
首先我 "manually" 在块 check_string 中附加一个 '/',然后在块 row_gen 中我生成与 '/' 的数量一样多的行.因此,对于像 L 4/0/2 这样的字符串,我需要生成 2+1(来自 check_string)行。
之后,我使用 instr 函数的组合对主字符串进行子字符串化,这将告诉我第一个、第二个和第三个“/”的字符位置。
最后,我加入主 table 以根据 table 中的实际值获取记录列表。
create table t(id int, name varchar(20), info varchar(50));
insert into t
select 1 ,'Isle 4 ','L 4' from dual union all
select 2 ,'Isle 0 ','L 5/0' from dual union all
select 3 ,'Isle 2 ','L 6/0/2' from dual union all
select 4 ,'Isle 2 ','L 4/2' from dual union all
select 5 ,'Isle 0 ','L 4/0' from dual union all
select 6 ,'Isle 0 ','L 5/0' from dual union all
select 7 ,'Isle 2 ','L 7/0/2' from dual union all
select 8 ,'Isle 3 ','L 8/3' from dual union all
select 9 ,'Isle 2 ','L 6/0/2' from dual union all
select 10,'Isle 2 ','L 4/0/2' from dual union all
select 11,'Isle 10','L 10' from dual union all
select 12,'Isle 0 ','L 11/0' from dual union all
select 13,'Isle 2 ','L 11/0/2' from dual;
with check_string
as (select 'L 4/0/2'||'/' as str /*Here you would pass the string that you want*/
from dual
)
,row_gen
as (
select level as lvl
,instr(str,'/',1,level) as col1
,substr(str
,1
,instr(str,'/',1,level)-1
) as col2
from dual
join check_string
on 1=1
connect by level<=length(str)-length(replace(str,'/'))
)
select *
from row_gen a
join t b
on a.col2=b.info
Output
+----+---------+---------+
| ID | NAME | INFO |
+----+---------+---------+
| 1 | Isle 4 | L 4 |
| 5 | Isle 0 | L 4/0 |
| 10 | Isle 2 | L 4/0/2 |
+----+---------+---------+
dbfiddle link
https://dbfiddle.uk/?rdbms=oracle_18&fiddle=7d974b5d936c04835e730113d28cd4d6
您可以按如下方式使用LIKE
和self join
:
SELECT T.* FROM
MY_INFO T JOIN MY_INTO T10
ON T10.INFO LIKE T.INFO || '%' -- (OR) ON INSTR(T10.INFO, T.INFO) = 1
WHERE T10.ID = 10;
环境:Oracle 12c
我在 table 中有以下数据集,称为:MY_INFO
ID NAME INFO
--------- --------- -----------
1 Isle 4 L 4
2 Isle 0 L 5/0
3 Isle 2 L 6/0/2
4 Isle 2 L 4/2
5 Isle 0 L 4/0
6 Isle 0 L 5/0
7 Isle 2 L 7/0/2
8 Isle 3 L 8/3
9 Isle 2 L 6/0/2
10 Isle 2 L 4/0/2
11 Isle 10 L 10
12 Isle 0 L 11/0
13 Isle 2 L 11/0/2
鉴于此 MY_INFO
table 中的上述记录并假设我使用的记录 ID:10,即:
ID NAME INFO
--------- --------- -----------
10 Isle 2 L 4/0/2
就像层次结构一样,我需要一种方法来检索遵循以下模式的所有记录,至少对于这条记录。
虽然在这种情况下,我只需要检索以下三个匹配的记录,相反,即
4
4/0
4/0/2
所以使用 INFO 值:L 4/0/2
,我现在需要分支到 L 4/0
并检索该记录,然后一直回到顶级记录 L 4
所以最后,我希望检索的记录是:
ID NAME INFO
--------- --------- -----------
1 Isle 4 L 4
5 Isle 0 L 4/0
10 Isle 2 L 4/0/2
不确定如何使用 SQL 解决此问题。
这里有一个方法...
首先我 "manually" 在块 check_string 中附加一个 '/',然后在块 row_gen 中我生成与 '/' 的数量一样多的行.因此,对于像 L 4/0/2 这样的字符串,我需要生成 2+1(来自 check_string)行。
之后,我使用 instr 函数的组合对主字符串进行子字符串化,这将告诉我第一个、第二个和第三个“/”的字符位置。
最后,我加入主 table 以根据 table 中的实际值获取记录列表。
create table t(id int, name varchar(20), info varchar(50));
insert into t
select 1 ,'Isle 4 ','L 4' from dual union all
select 2 ,'Isle 0 ','L 5/0' from dual union all
select 3 ,'Isle 2 ','L 6/0/2' from dual union all
select 4 ,'Isle 2 ','L 4/2' from dual union all
select 5 ,'Isle 0 ','L 4/0' from dual union all
select 6 ,'Isle 0 ','L 5/0' from dual union all
select 7 ,'Isle 2 ','L 7/0/2' from dual union all
select 8 ,'Isle 3 ','L 8/3' from dual union all
select 9 ,'Isle 2 ','L 6/0/2' from dual union all
select 10,'Isle 2 ','L 4/0/2' from dual union all
select 11,'Isle 10','L 10' from dual union all
select 12,'Isle 0 ','L 11/0' from dual union all
select 13,'Isle 2 ','L 11/0/2' from dual;
with check_string
as (select 'L 4/0/2'||'/' as str /*Here you would pass the string that you want*/
from dual
)
,row_gen
as (
select level as lvl
,instr(str,'/',1,level) as col1
,substr(str
,1
,instr(str,'/',1,level)-1
) as col2
from dual
join check_string
on 1=1
connect by level<=length(str)-length(replace(str,'/'))
)
select *
from row_gen a
join t b
on a.col2=b.info
Output
+----+---------+---------+
| ID | NAME | INFO |
+----+---------+---------+
| 1 | Isle 4 | L 4 |
| 5 | Isle 0 | L 4/0 |
| 10 | Isle 2 | L 4/0/2 |
+----+---------+---------+
dbfiddle link
https://dbfiddle.uk/?rdbms=oracle_18&fiddle=7d974b5d936c04835e730113d28cd4d6
您可以按如下方式使用LIKE
和self join
:
SELECT T.* FROM
MY_INFO T JOIN MY_INTO T10
ON T10.INFO LIKE T.INFO || '%' -- (OR) ON INSTR(T10.INFO, T.INFO) = 1
WHERE T10.ID = 10;