假设我有一个名为'公司'的视图,我无法修改:
+------------+--------------------+--------+--------+------------------------+
| company_id | company_name | ceo | cfo | legal_contacts |
+------------+--------------------+--------+--------+------------------------+
| 1 | johnson and son | pid111 | pid333 | pid444, pid567, pid999 |
| 2 | Pepperville apples | pid777 | | pid345 |
| 3 | Cats LTD | pid123 | pid321 | |
+------------+--------------------+--------+--------+------------------------+
还有一个名为'contacts'的视图:
+-----------+-------+----------------------+
| person_id | name | email |
+-----------+-------+----------------------+
| pid111 | john | john@gmail.com |
| pid333 | steve | funkylover@mail.com |
| pid444 | mary | mar123@ymail.com |
| pid999 | joe | joe.bloggs@gmail.com |
| pid777 | louis | |
| pid345 | carol | carol@carolssite.com |
| pid321 | ellen | ellen.deg@gmail.com |
+-----------+-------+----------------------+
最终目标是让我编写一个交叉引用人员ID并显示电子邮件和公司的查询:
+---------+----------------+-----------------------------------------+
| company | ceo | legal_contacts |
+---------+----------------+-----------------------------------------+
| 1 | john@gmail.com | mary123@ymail.com, joe.bloggs@gmail.com |
| 2 | | carol@carossite.com |
| 3 | | |
+---------+----------------+-----------------------------------------+
在没有编写函数或进程的情况下,我有没有办法在查询中加入或处理这个以逗号分隔的标识符列表?
您可以假设“合法联系人”最多包含25个标识符,始终采用相同格式,始终以逗号分隔
答案 0 :(得分:1)
这是一种糟糕的数据格式,但您似乎知道这一点。这是一种方法:
select c.company, c.ceo,
listagg(co.email, ', ') within group (order by co.person_id) as emails
from companies c join
contacts co
on ', ' || legal_contacts || ', ' like '%, ' || co.person_id || ',%'
group by c.company, c.ceo ;
答案 1 :(得分:1)
您可以使用正则表达式拆分companies.legal_contacts
列表,然后将结果集与联系人一起加入以获取电子邮件地址(加入两次以获取ceo
邮件)然后重新连接电子邮件使用listagg
函数:
SELECT co.company_id, p1.email, LISTAGG(p2.email, ', ') WITHIN GROUP (ORDER BY p2.email)
FROM (
SELECT DISTINCT company_id, ceo, REGEXP_SUBSTR(legal_contacts, '[^, ]+', 1, LEVEL) AS single_contact
FROM COMPANIES
CONNECT BY REGEXP_SUBSTR(legal_contacts, '[^, ]+', 1, LEVEL) IS NOT NULL) co
LEFT JOIN CONTACTS p1 ON co.ceo = p1.person_id
LEFT JOIN CONTACTS p2 ON co.single_contact = p2.person_id
GROUP BY co.company_id, p1.email;
如果companies.legal_contacts
可以包含许多值,则出于性能原因,正则表达式的使用会发生一些变化,您必须使用MULTISET。
答案 2 :(得分:0)
您还可以编写一个帮助您规范化数据的函数(pehpaps创建您自己的视图)
CREATE OR REPLACE TYPE VARCHAR_TABLE_TYPE AS TABLE OF VARCHAR2(1000);
CREATE OR REPLACE FUNCTION SplitString(LIST IN VARCHAR2, Separator IN VARCHAR2) RETURN VARCHAR_TABLE_TYPE IS
OutTable VARCHAR_TABLE_TYPE;
BEGIN
SELECT TRIM(REGEXP_SUBSTR(LIST, '[^'||Separator||']+', 1, LEVEL))
BULK COLLECT INTO OutTable
FROM dual
CONNECT BY REGEXP_SUBSTR(LIST, '[^'||Separator||']+', 1, LEVEL) IS NOT NULL;
RETURN OutTable;
END SplitString;
然后查询将是:
WITH com AS
(SELECT company_id, company_name, ceo, cfo,
imp_util.SplitString(legal_contacts, ', ') AS legal_contacts
FROM companies)
SELECT company_id, ceo.email AS ceo,
LISTAGG(legal.email, ', ') WITHIN GROUP (ORDER BY legal.person_id) AS emails
FROM com
LEFT OUTER JOIN contacts legal ON legal.person_id MEMBER OF legal_contacts
LEFT OUTER JOIN contacts ceo ON ceo.person_id = ceo
GROUP BY company_id, ceo.email;
答案 3 :(得分:-1)
SQL> WITH companies (company_id, ceo, legal_contacts)
2 AS (SELECT 1, 'pid111', 'pid444, pid567, pid999' FROM DUAL
3 UNION
4 SELECT 2, 'pid777', 'pid345' FROM DUAL
5 UNION
6 SELECT 3, 'pid123', NULL FROM DUAL),
7 contacts (person_id, email)
8 AS (SELECT 'pid111', 'john@gmail.com' FROM DUAL
9 UNION
10 SELECT 'pid333', 'funkylover@mail.com' FROM DUAL
11 UNION
12 SELECT 'pid444', 'mar123@ymail.com' FROM DUAL
13 UNION
14 SELECT 'pid999', 'joe.bloggs@gmail.com' FROM DUAL
15 UNION
16 SELECT 'pid777', NULL FROM DUAL
17 UNION
18 SELECT 'pid345', 'carol@carolssite.com' FROM DUAL
19 UNION
20 SELECT 'pid321', 'ellen.deg@gmail.com' FROM DUAL),
21 sco
22 AS (SELECT company_id,
23 ceo,
24 REGEXP_SUBSTR (REPLACE (legal_contacts, ' ', ''),
25 '[^,]+',
26 1,
27 x.COLUMN_VALUE)
28 person_id
29 FROM companies,
30 TABLE (
31 CAST (
32 MULTISET (
33 SELECT LEVEL
34 FROM DUAL
35 CONNECT BY LEVEL <=
36 REGEXP_COUNT (legal_contacts, ',') + 1) AS SYS.odcivarchar2list)) x)
37 SELECT s.company_id,
38 c1.email ceo,
39 LISTAGG (c2.email, ', ') WITHIN GROUP (ORDER BY c2.email)
40 legal_contacts
41 FROM sco s
42 LEFT OUTER JOIN contacts c1 ON c1.person_id = s.ceo
43 LEFT OUTER JOIN contacts c2 ON c2.person_id = s.person_id
44 GROUP BY s.company_id, c1.email;
COMPANY_ID CEO LEGAL_CONTACTS
---------- -------------------- ----------------------------------------
1 john@gmail.com joe.bloggs@gmail.com, mar123@ymail.com
2 carol@carolssite.com
3
SQL>