基于字符串模式检索父记录的 Oracle SQL 查询

Posted

技术标签:

【中文标题】基于字符串模式检索父记录的 Oracle SQL 查询【英文标题】:Oracle SQL query to retrieve parent records based on a string pattern 【发布时间】:2020-05-13 02:28:56 【问题描述】:

环境:Oracle 12c

我在一个名为的表中有以下数据集: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 表中的上述记录并假设我使用的记录 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 解决此问题。

【问题讨论】:

【参考方案1】:

这是一种方法...

首先,我“手动”在块 check_string 中附加一个“/”,然后在块 row_gen 中生成与“/”数量一样多的行。所以对于像 L 4/0/2 这样的字符串,我需要 2+1(from check_string) 行来生成。

然后我用 instr 函数的组合对主字符串进行子串化,这将告诉我第一个、第二个和第三个'/'的字符位置。

最后我加入主表,根据表中的实际值获取记录列表。

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 链接

https://dbfiddle.uk/?rdbms=oracle_18&fiddle=7d974b5d936c04835e730113d28cd4d6

【讨论】:

【参考方案2】:

您可以使用LIKEself 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 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

Oracle Sqoop 检索到 0 条记录

Oracle 12 PL/SQL 在触发器中检索存储过程名称

Oracle sql查询需要根据时区变化

ORACLE PL/SQL - 使用 SYSDATE 检索特定日期的数据时出现检索问题

Oracle全文检索是啥意思?

Oracle递归查询(查询当前记录所有父级或子级)