你可以用简单的字符串函数来做到这一点:
WITH t1_positions (id, name, spos, epos) AS (
SELECT id,
name,
1,
INSTR(name, ';', 1)
FROM table1
UNION ALL
SELECT id,
name,
epos + 1,
INSTR(name, ';', epos + 1)
FROM t1_positions
WHERE epos > 0
),
t1_strings (id, item) AS (
SELECT id,
CASE epos
WHEN 0
THEN SUBSTR(name, spos)
ELSE SUBSTR(name, spos, epos - spos)
END
FROM t1_positions
),
t2_positions (id, name, spos, epos) AS (
SELECT id,
name,
1,
INSTR(name, ';', 1)
FROM table2
UNION ALL
SELECT id,
name,
epos + 1,
INSTR(name, ';', epos + 1)
FROM t2_positions
WHERE epos > 0
),
t2_strings (id, item) AS (
SELECT id,
CASE epos
WHEN 0
THEN SUBSTR(name, spos)
ELSE SUBSTR(name, spos, epos - spos)
END
FROM t2_positions
)
SELECT id,
LISTAGG(item, ';') WITHIN GROUP (ORDER BY item) AS name
FROM (SELECT * FROM t1_strings
UNION
SELECT * FROM t2_strings)
GROUP BY id;
其中,对于样本数据:
CREATE TABLE Table1 (id, name) AS
SELECT 1, 'John;Sue' FROM DUAL;
CREATE TABLE Table2 (id, name) AS
SELECT 1, 'Mary;John' FROM DUAL;
输出:
注意:你可以用正则表达式来做;但是,对于大型数据集,它可能会慢一个数量级。
更新
如何在 Oracle 中正确地做到这一点?
不存储分隔字符串,以第一范式(1NF)存储数据:
CREATE TABLE table1 (id, name) AS
SELECT 1, 'John' FROM DUAL UNION ALL
SELECT 1, 'Sue' FROM DUAL;
CREATE TABLE table2 (id, name) AS
SELECT 1, 'Mary' FROM DUAL UNION ALL
SELECT 1, 'John' FROM DUAL;
那么查询很简单:
SELECT id,
LISTAGG(name, ';') WITHIN GROUP (ORDER BY name) AS name
FROM (SELECT * FROM table1
UNION
SELECT * FROM table2)
GROUP BY id;
db小提琴here