递归查询加入结果集与table只要有更多的匹配
Recursive query to join the result set with the table as long as there are more matches
CUSTOMER
customer_id | email1 | email2 | phone1 | phone2
REGISTRATION
registration_id | email3 | ip
REGISTRATION_TO_CUSTOMER
registration_id | customer_id | email4
BANNED
banned_id | ip | email | phone
数据样本:
CUSTOMER
1 | test1_1@mail.com | test1_2@mail.com | 1 | 11|
2 | test2_1@mail.com | test2_2@mail.com | 2 | 1 |
3 | test3_1@mail.com | test3_2@mail.com | 3 | 33|
REGISTRATION
1 | test1_1a@mail.com | 192.168.1.1
2 | test2_1a@mail.com | 192.168.1.3
3 | test3_1a@mail.com | 192.168.1.3
REGISTRATION_TO_CUSTOMER
1 | 1 | test1_1a@mail.com
2 | 2 | test2_1b@mail.com
3 | 3 | test3_1c@mail.com
BANNED
1 | 192.168.1.3 | null | null
3 | null | test2@mail.com | null
解释:
BANNED有2条记录,但我有3个客户
匹配禁止和客户的查询将 return 2 个 ID#2 和 ID#3 的客户,因为他们在 Banned table.
中有匹配数据
- 问题:客户#3 与客户#1 有相同的phone;因此 客户 #1 也需要列出。因此,我需要用 BANNED 递归地(根据需要多次)加入 ResultSet 以重新查询数据库并获取所有可能链接客户的完整列表
所以我尝试了这个(但 return 没有任何结果):
SELECT DISTINCT customer_id,
email1,
email2,
email3,
email4,
phone1,
phone2,
ip
FROM (
SELECT *
FROM (
SELECT r.ip,
r.registration_id,
r.email3,
rc.email4,
c.customer_id,
c.email1,
c.email2,
c.phone1,
c.phone2
FROM (
SELECT registration_id,
email3,
ip
FROM REGISTRATION
) r
INNER JOIN (
SELECT registration_id,
customer_id,
email4
FROM REGISTRATION_TO_CUSTOMER
) rc
ON r.registration_id = rc.registration_id
INNER JOIN (
SELECT customer_id,
email1,
email2,
phone1,
phone2
FROM CUSTOMER
) c
ON rc.customer_id = c.customer_id
) start WITH (
email1,
email2,
email3,
email4,
phone1,
phone2,
ip
) IN (
SELECT DISTINCT CUST.email1,
CUST.email2,
CUST.email3,
CUST.email4,
CUST.phone1,
CUST.phone2,
CUST.ip
FROM (
SELECT r.ip,
r.registration_id,
r.email3,
rc.email4,
c.customer_id,
c.email1,
c.email2,
c.phone1,
c.phone2
FROM (
SELECT registration_id,
email3,
ip
FROM REGISTRATION
) r
INNER JOIN (
SELECT registration_id,
customer_id,
email4
FROM REGISTRATION_TO_CUSTOMER
) rc
ON r.registration_id = rc.registration_id
INNER JOIN (
SELECT customer_id,
email1,
email2,
phone1,
phone2
FROM CUSTOMER
) c
ON rc.customer_id = c.customer_id
) CUST
INNER JOIN BANNED
ON CUST.ip = BANNED.ip
OR CUST.email1 = BANNED.email
OR CUST.email2 = BANNED.email
OR CUST.email3 = BANNED.email
OR CUST.email4 = BANNED.email
OR CUST.phone1 = BANNED.phone
OR CUST.phone2 = BANNED.phone
) connect BY nocycle email1 = prior email1
OR email2 = prior email2
OR email3 = prior email3
OR email4 = prior email4
OR phone1 = prior phone1
OR phone2 = prior phone2
OR ip = prior ip
)
ORDER BY customer_id
这个查询看起来很有希望:
select distinct id, ip, email, phone
from (
select id, ip, email, phone,
from customer start with
(ip, email, phone) in (
select distinct c.ip, c.email, c.phone
from customer c join banned b
on b.ip = c.ip or b.email = c.email or b.phone = c.phone)
connect by nocycle ip = prior ip or email = prior email or phone = prior phone)
order by id
这里是fiddle。
编辑:修改后的查询考虑了新表,在问题中添加:registration, registration_to_customer
以及其他电话和电子邮件。
with cust as (
select customer_id cid, registration_id rid, ip, phone1, phone2,
email1, email2, email3, email4
from registration r
join registration_to_customer rc using (registration_id)
join customer using (customer_id))
select distinct cid, rid, ip, phone1, phone2, email1, email2, email3, email4
from cust
start with (ip, phone1, phone2, email1, email2, email3, email4)
in (
select b.ip, phone1, phone2, email1, email2, email3, email4 from cust
join banned b on b.ip = cust.ip
or b.email in (cust.email1, cust.email2, cust.email3, cust.email4)
or b.phone in (cust.phone1, cust.phone2))
connect by nocycle
email1 in (prior email1, prior email2, prior email3, prior email4) or
email2 in (prior email1, prior email2, prior email3, prior email4) or
email3 in (prior email1, prior email2, prior email3, prior email4) or
email4 in (prior email1, prior email2, prior email3, prior email4) or
phone1 in (prior phone1, prior phone2) or
phone2 in (prior phone1, prior phone2) or
ip = prior ip
order by cid
CUSTOMER
customer_id | email1 | email2 | phone1 | phone2
REGISTRATION
registration_id | email3 | ip
REGISTRATION_TO_CUSTOMER
registration_id | customer_id | email4
BANNED
banned_id | ip | email | phone
数据样本:
CUSTOMER
1 | test1_1@mail.com | test1_2@mail.com | 1 | 11|
2 | test2_1@mail.com | test2_2@mail.com | 2 | 1 |
3 | test3_1@mail.com | test3_2@mail.com | 3 | 33|
REGISTRATION
1 | test1_1a@mail.com | 192.168.1.1
2 | test2_1a@mail.com | 192.168.1.3
3 | test3_1a@mail.com | 192.168.1.3
REGISTRATION_TO_CUSTOMER
1 | 1 | test1_1a@mail.com
2 | 2 | test2_1b@mail.com
3 | 3 | test3_1c@mail.com
BANNED
1 | 192.168.1.3 | null | null
3 | null | test2@mail.com | null
解释:
BANNED有2条记录,但我有3个客户
匹配禁止和客户的查询将 return 2 个 ID#2 和 ID#3 的客户,因为他们在 Banned table.
中有匹配数据- 问题:客户#3 与客户#1 有相同的phone;因此 客户 #1 也需要列出。因此,我需要用 BANNED 递归地(根据需要多次)加入 ResultSet 以重新查询数据库并获取所有可能链接客户的完整列表
所以我尝试了这个(但 return 没有任何结果):
SELECT DISTINCT customer_id,
email1,
email2,
email3,
email4,
phone1,
phone2,
ip
FROM (
SELECT *
FROM (
SELECT r.ip,
r.registration_id,
r.email3,
rc.email4,
c.customer_id,
c.email1,
c.email2,
c.phone1,
c.phone2
FROM (
SELECT registration_id,
email3,
ip
FROM REGISTRATION
) r
INNER JOIN (
SELECT registration_id,
customer_id,
email4
FROM REGISTRATION_TO_CUSTOMER
) rc
ON r.registration_id = rc.registration_id
INNER JOIN (
SELECT customer_id,
email1,
email2,
phone1,
phone2
FROM CUSTOMER
) c
ON rc.customer_id = c.customer_id
) start WITH (
email1,
email2,
email3,
email4,
phone1,
phone2,
ip
) IN (
SELECT DISTINCT CUST.email1,
CUST.email2,
CUST.email3,
CUST.email4,
CUST.phone1,
CUST.phone2,
CUST.ip
FROM (
SELECT r.ip,
r.registration_id,
r.email3,
rc.email4,
c.customer_id,
c.email1,
c.email2,
c.phone1,
c.phone2
FROM (
SELECT registration_id,
email3,
ip
FROM REGISTRATION
) r
INNER JOIN (
SELECT registration_id,
customer_id,
email4
FROM REGISTRATION_TO_CUSTOMER
) rc
ON r.registration_id = rc.registration_id
INNER JOIN (
SELECT customer_id,
email1,
email2,
phone1,
phone2
FROM CUSTOMER
) c
ON rc.customer_id = c.customer_id
) CUST
INNER JOIN BANNED
ON CUST.ip = BANNED.ip
OR CUST.email1 = BANNED.email
OR CUST.email2 = BANNED.email
OR CUST.email3 = BANNED.email
OR CUST.email4 = BANNED.email
OR CUST.phone1 = BANNED.phone
OR CUST.phone2 = BANNED.phone
) connect BY nocycle email1 = prior email1
OR email2 = prior email2
OR email3 = prior email3
OR email4 = prior email4
OR phone1 = prior phone1
OR phone2 = prior phone2
OR ip = prior ip
)
ORDER BY customer_id
这个查询看起来很有希望:
select distinct id, ip, email, phone
from (
select id, ip, email, phone,
from customer start with
(ip, email, phone) in (
select distinct c.ip, c.email, c.phone
from customer c join banned b
on b.ip = c.ip or b.email = c.email or b.phone = c.phone)
connect by nocycle ip = prior ip or email = prior email or phone = prior phone)
order by id
这里是fiddle。
编辑:修改后的查询考虑了新表,在问题中添加:registration, registration_to_customer
以及其他电话和电子邮件。
with cust as (
select customer_id cid, registration_id rid, ip, phone1, phone2,
email1, email2, email3, email4
from registration r
join registration_to_customer rc using (registration_id)
join customer using (customer_id))
select distinct cid, rid, ip, phone1, phone2, email1, email2, email3, email4
from cust
start with (ip, phone1, phone2, email1, email2, email3, email4)
in (
select b.ip, phone1, phone2, email1, email2, email3, email4 from cust
join banned b on b.ip = cust.ip
or b.email in (cust.email1, cust.email2, cust.email3, cust.email4)
or b.phone in (cust.phone1, cust.phone2))
connect by nocycle
email1 in (prior email1, prior email2, prior email3, prior email4) or
email2 in (prior email1, prior email2, prior email3, prior email4) or
email3 in (prior email1, prior email2, prior email3, prior email4) or
email4 in (prior email1, prior email2, prior email3, prior email4) or
phone1 in (prior phone1, prior phone2) or
phone2 in (prior phone1, prior phone2) or
ip = prior ip
order by cid