【发布时间】:2020-06-01 08:14:33
【问题描述】:
我如何编写 SQL 以使其返回给我
tom,ken,jerry
我试过这个 SQL
select name
from staffDB
where dept in (select value
from ConfigDB
where key = 'dept')
但它不返回任何值,不,不,我不允许更改数据库设计。
【问题讨论】:
我如何编写 SQL 以使其返回给我
tom,ken,jerry
我试过这个 SQL
select name
from staffDB
where dept in (select value
from ConfigDB
where key = 'dept')
但它不返回任何值,不,不,我不允许更改数据库设计。
【问题讨论】:
您的数据库设计不是最优的,因为它存储的是 CSV 值。话虽如此,这是使用LISTAGG (11g+) 获得所需输出的一种方法:
SELECT
c."Key",
LISTAGG(s.Name, ',') WITHIN GROUP (ORDER BY s.Dept) Departments
FROM ConfigDB c
LEFT JOIN StaffDB s
ON ',' || c."Value" || ',' LIKE '%,' || s.Dept || '%,'
GROUP BY
c."Key";
请注意,我们使用此逻辑将 config 表中的部门 CSV 列表与 staff 表中的每个标量值进行比较,例如:
,A,B,C, LIKE '%,A,%'
也就是说,我们将逗号标记到部门的 CSV 字符串上,以便我们可以搜索用逗号包围的每个可能的标量部门。
【讨论】:
一种选择是用逗号分隔,然后通过在SELECT .. CONNECT BY level .. 语句中使用LISTAGG() 函数进行组合:
WITH ConfigDB( key, value ) AS
(
SELECT 'dept', 'A,B,C' FROM dual
), StaffDB( name, dept ) AS
(
SELECT 'tom' , 'A' FROM dual UNION ALL
SELECT 'ken' , 'B' FROM dual UNION ALL
SELECT 'jerry', 'C' FROM dual
), t AS
(
SELECT REGEXP_SUBSTR(value,'[^,]',1,level) AS letter, level AS lvl
FROM ConfigDB
CONNECT BY level <= REGEXP_COUNT(value,',') + 1
)
SELECT LISTAGG(name,',') WITHIN GROUP (ORDER BY lvl) AS DBNAme
FROM t
JOIN StaffDB
ON dept = letter
【讨论】:
您可以使用层次查询来拆分值,然后将其连接起来,如下所示:
SQL> SELECT
2 C.KEY,
3 LISTAGG(S.NAME, ',') WITHIN GROUP(ORDER BY S.DEPT) DEPARTMENTS
4 FROM
5 CONFIGDB C
6 CROSS JOIN TABLE ( CAST(MULTISET(
7 SELECT REGEXP_SUBSTR(C.VALUE, '[^,]+', 1, LEVEL)
8 FROM DUAL
9 CONNECT BY LEVEL <= REGEXP_COUNT(C.VALUE, '[^,]+')
10 ) AS SYS.ODCIVARCHAR2LIST) ) C1
11 LEFT JOIN STAFFDB S ON S.DEPT = C1.COLUMN_VALUE
12 GROUP BY C.KEY;
KEY DEPARTMENTS
----- ---------------
dept tom,ken,jerry
SQL>
【讨论】: