Oracle 从多个数据库表中查找字符串匹配
Oracle Finding a string match from multiple database tables
这个问题描述起来有点复杂,但我会尝试用一个例子来解释它。我以为我可以使用 Oracle Instr 函数来完成此操作,但它不接受查询作为参数。
这里是我的数据的简化:
Table1
Person Qualities
Joe 5,6,7,8,9
Mary 7,8,10,15,20
Bob 7,8,9,10,11,12
Table2
Id Desc
5 Nice
6 Tall
7 Short
Table3
Id Desc
8 Angry
9 Sad
10 Fun
Table4
Id Desc
11 Boring
12 Happy
15 Cool
20 Mad
这里有一些查询可以让您了解我要完成的任务:
select * from table1
where instr (Qualities, select Id from table2, 1,1) <> 0
and instr (Qualities, select Id from table3, 1,1) <> 0
and instr (Qualities, select Id from table3, 1,1) <> 0
我试图找出哪些人至少具有 3 组品质(表 2、3 和 4)中的每一种品质
所以 Joe 不会在结果中返回,因为他不具备 3 个组中每个组的质量,但 Mary 和 Joe 会返回,因为他们每个组至少有 1 个质量。
我们是 运行 Oracle 12,谢谢!
这是一种选择:
SQL> with
2 table1 (person, qualities) as
3 (select 'Joe', '5,6,7,8,9' from dual union all
4 select 'Mary', '7,8,10,15,20' from dual union all
5 select 'Bob', '7,8,9,10,11,12' from dual
6 ),
7 table2 (id, descr) as
8 (select 5, 'Nice' from dual union all
9 select 6, 'Tall' from dual union all
10 select 7, 'Short' from dual
11 ),
12 table3 (id, descr) as
13 (select 8, 'Angry' from dual union all
14 select 9, 'Sad' from dual union all
15 select 10, 'Fun' from dual
16 ),
17 table4 (id, descr) as
18 (select 11, 'Boring' from dual union all
19 select 12, 'Happy' from dual union all
20 select 15, 'Cool' from dual union all
21 select 20, 'Mad' from dual
22 ),
23 t1new (person, id) as
24 (select person, regexp_substr(qualities, '[^,]+', 1, column_value) id
25 from table1 cross join table(cast(multiset(select level from dual
26 connect by level <= regexp_count(qualities, ',') + 1
27 ) as sys.odcinumberlist))
28 )
29 select a.person,
30 count(b.id) bid,
31 count(c.id) cid,
32 count(d.id) did
33 from t1new a left join table2 b on a.id = b.id
34 left join table3 c on a.id = c.id
35 left join table4 d on a.id = d.id
36 group by a.person
37 having ( count(b.id) > 0
38 and count(c.id) > 0
39 and count(d.id) > 0
40 );
PERS BID CID DID
---- ---------- ---------- ----------
Bob 1 3 2
Mary 1 2 2
SQL>
它有什么作用?
- 第 1 - 22 行代表您的样本数据
T1NEW
CTE(第 23 - 28 行)将每个人的逗号分隔质量分成几行
- final
select
(第 29 - 40 行)是外部连接 t1new
与每个 "description" 表(table2/3/4
)并计算其中包含多少质量每个人的品质(由 t1new
中的行表示)
having
子句是这里 return 只需要的人;这些计数中的每一个都必须是正数
也许这会有所帮助:
{1} 创建一个对所有质量进行分类并允许您 SELECT 质量 ID 和类别的视图。 {2} 将视图联接到 TABLE1 并使用 "splits" 存储在 TABLE1 中的 CSV 值的联接条件。
{1} 查看
create or replace view allqualities
as
select 1 as category, id as qid, descr from table2
union
select 2, id, descr from table3
union
select 3, id, descr from table4
;
select * from allqualities order by category, qid ;
CATEGORY QID DESCR
---------- ---------- ------
1 5 Nice
1 6 Tall
1 7 Short
2 8 Angry
2 9 Sad
2 10 Fun
3 11 Boring
3 12 Happy
3 15 Cool
3 20 Mad
{2}查询
-- JOIN CONDITION:
-- {1} add a comma at the start and at the end of T1.qualities
-- {2} remove all blanks (spaces) from T1.qualities
-- {3} use LIKE and the qid (of allqualities), wrapped in commas
--
-- inline view: use UNIQUE, otherwise we may get counts > 3
--
select person
from (
select unique person, category
from table1 T1
join allqualities A
on ',' || replace( T1.qualities, ' ', '' ) || ',' like '%,' || A.qid || ',%'
)
group by person
having count(*) = ( select count( distinct category ) from allqualities )
;
-- result
PERSON
Bob
Mary
使用 Oracle 18c 和 11g 进行了测试。 DBfiddle here.
这个问题描述起来有点复杂,但我会尝试用一个例子来解释它。我以为我可以使用 Oracle Instr 函数来完成此操作,但它不接受查询作为参数。
这里是我的数据的简化:
Table1
Person Qualities
Joe 5,6,7,8,9
Mary 7,8,10,15,20
Bob 7,8,9,10,11,12
Table2
Id Desc
5 Nice
6 Tall
7 Short
Table3
Id Desc
8 Angry
9 Sad
10 Fun
Table4
Id Desc
11 Boring
12 Happy
15 Cool
20 Mad
这里有一些查询可以让您了解我要完成的任务:
select * from table1
where instr (Qualities, select Id from table2, 1,1) <> 0
and instr (Qualities, select Id from table3, 1,1) <> 0
and instr (Qualities, select Id from table3, 1,1) <> 0
我试图找出哪些人至少具有 3 组品质(表 2、3 和 4)中的每一种品质
所以 Joe 不会在结果中返回,因为他不具备 3 个组中每个组的质量,但 Mary 和 Joe 会返回,因为他们每个组至少有 1 个质量。
我们是 运行 Oracle 12,谢谢!
这是一种选择:
SQL> with
2 table1 (person, qualities) as
3 (select 'Joe', '5,6,7,8,9' from dual union all
4 select 'Mary', '7,8,10,15,20' from dual union all
5 select 'Bob', '7,8,9,10,11,12' from dual
6 ),
7 table2 (id, descr) as
8 (select 5, 'Nice' from dual union all
9 select 6, 'Tall' from dual union all
10 select 7, 'Short' from dual
11 ),
12 table3 (id, descr) as
13 (select 8, 'Angry' from dual union all
14 select 9, 'Sad' from dual union all
15 select 10, 'Fun' from dual
16 ),
17 table4 (id, descr) as
18 (select 11, 'Boring' from dual union all
19 select 12, 'Happy' from dual union all
20 select 15, 'Cool' from dual union all
21 select 20, 'Mad' from dual
22 ),
23 t1new (person, id) as
24 (select person, regexp_substr(qualities, '[^,]+', 1, column_value) id
25 from table1 cross join table(cast(multiset(select level from dual
26 connect by level <= regexp_count(qualities, ',') + 1
27 ) as sys.odcinumberlist))
28 )
29 select a.person,
30 count(b.id) bid,
31 count(c.id) cid,
32 count(d.id) did
33 from t1new a left join table2 b on a.id = b.id
34 left join table3 c on a.id = c.id
35 left join table4 d on a.id = d.id
36 group by a.person
37 having ( count(b.id) > 0
38 and count(c.id) > 0
39 and count(d.id) > 0
40 );
PERS BID CID DID
---- ---------- ---------- ----------
Bob 1 3 2
Mary 1 2 2
SQL>
它有什么作用?
- 第 1 - 22 行代表您的样本数据
T1NEW
CTE(第 23 - 28 行)将每个人的逗号分隔质量分成几行- final
select
(第 29 - 40 行)是外部连接t1new
与每个 "description" 表(table2/3/4
)并计算其中包含多少质量每个人的品质(由t1new
中的行表示) having
子句是这里 return 只需要的人;这些计数中的每一个都必须是正数
也许这会有所帮助: {1} 创建一个对所有质量进行分类并允许您 SELECT 质量 ID 和类别的视图。 {2} 将视图联接到 TABLE1 并使用 "splits" 存储在 TABLE1 中的 CSV 值的联接条件。
{1} 查看
create or replace view allqualities
as
select 1 as category, id as qid, descr from table2
union
select 2, id, descr from table3
union
select 3, id, descr from table4
;
select * from allqualities order by category, qid ;
CATEGORY QID DESCR
---------- ---------- ------
1 5 Nice
1 6 Tall
1 7 Short
2 8 Angry
2 9 Sad
2 10 Fun
3 11 Boring
3 12 Happy
3 15 Cool
3 20 Mad
{2}查询
-- JOIN CONDITION:
-- {1} add a comma at the start and at the end of T1.qualities
-- {2} remove all blanks (spaces) from T1.qualities
-- {3} use LIKE and the qid (of allqualities), wrapped in commas
--
-- inline view: use UNIQUE, otherwise we may get counts > 3
--
select person
from (
select unique person, category
from table1 T1
join allqualities A
on ',' || replace( T1.qualities, ' ', '' ) || ',' like '%,' || A.qid || ',%'
)
group by person
having count(*) = ( select count( distinct category ) from allqualities )
;
-- result
PERSON
Bob
Mary
使用 Oracle 18c 和 11g 进行了测试。 DBfiddle here.