如何将多自连接查询转换为递归 CTE

How to turn a multiple self Join query into a recursive CTE

我希望有人能慢慢地向我解释这个,因为从我读过的所有内容来看,我似乎不明白如何做我想做的事。

我有一个包含 IP 和电子邮件列的 table。我收到一封电子邮件,我需要寻找相应的 Ips,但它并没有就此结束,然后我需要寻找那些新 Ips 的电子邮件,然后是这些电子邮件的 Ips,依此类推,直到没有更多新电子邮件为止和 Ips。

我可以这样做:

SELECT DISTINCT t.CUSTOMER_IP, t.CUSTOMER_EMAIL
   FROM [Main table] t
          INNER JOIN [Main table] t1 ON (t.CUSTOMER_IP = t1.CUSTOMER_IP)
          INNER JOIN [Main table] t2 ON (t1.CUSTOMER_EMAIL = t2.CUSTOMER_EMAIL)
          INNER JOIN [Main table] t3 ON (t2.CUSTOMER_IP = t3.CUSTOMER_IP)
   WHERE t3.CUSTOMER_EMAIL = 'ejskslsks@gmail.com'
           AND t1.CUSTOMER_IP IS NOT NULL
        AND t2.CUSTOMER_IP IS NOT NULL
        AND t3.CUSTOMER_IP IS NOT NULL
        and t.ISSUE_DATE BETWEEN '2015-02-23 00:00:00' AND '2015-02-23 23:59:59' 

到目前为止一切顺利,除了这限制了我的搜索,我需要创建某种递归查询,例如:

WITH iptable as
(
SELECT DISTINCT CUSTOMER_IP, customer_email, 1 as loopy
       FROM [Main table]
       WHERE CUSTOMER_EMAIL = 'ejskslsks@gmail.com'
       AND ISSUE_DATE BETWEEN '2015-02-23 00:00:00' AND '2015-02-23 23:59:59'
       AND CUSTOMER_IP IS NOT NULL
union all
SELECT t.CUSTOMER_IP, t.CUSTOMER_EMAIL, iptable.loopy +1 as loopy
    FROM [Main table] t
              INNER JOIN iptable ON (iptable.CUSTOMER_IP = t.CUSTOMER_IP)
              INNER JOIN [Main table] t1 ON (t.CUSTOMER_EMAIL = t1.CUSTOMER_EMAIL)
    where t.ISSUE_DATE BETWEEN '2015-02-23 00:00:00' AND '2015-02-23 23:59:59' 
    and iptable.loopy <2

)
Select DISTINCT CUSTOMER_IP, CUSTOMER_EMAIL from iptable

loopy 列只是为了能够控制迭代次数,在这个例子中只有 2 次。这只会给我新的电子邮件,因为它不会从这些电子邮件中寻找新的 ips。

我不知道如何解决这个问题,我是 SQL 初学者。我还需要提供其他信息吗?也许 CTE 不是最好的方法?我考虑过 WHILE 查询,但我必须使用 temptables,我想尽可能避免使用它们。

提前致谢!

你需要一种方法 在 select 工会下 select 时包含父记录,否则你将有大量中间结果集(对性能产生负面影响)。这绝对不是 SQL 最好的事情。

此外 - 您可以在多个条件下加入(CUSTOMER_EMAIL 或 CUSTOMER_IP) - 从而避免多次加入相同的 table。

我喜欢 select 声明 使用 cte 是限制结果的那个 - 并且只在 cte 中包含特定于关系的内容.他们一开始就让人头晕目眩。可能是这样的:

with iptable (ROOT_EMAIL, CUSTOMER_IP, CUSTOMER_EMAIL, ISSUE_DATE, DEPTH )as
(
    select top (1)
        parent.CUSTOMER_EMAIL ROOT_EMAIL,
        parent.CUSTOMER_IP,
        parent.CUSTOMER_EMAIL,
        parent.ISSUE_DATE, 
        1 as DEPTH
    from
        [Main table] parent
    where
        parent.CUSTOMER_IP is not null
    order by 
        parent.ISSUE_DATE

    union all

    select
        parent.ROOT_EMAIL,
        child.CUSTOMER_IP,
        child.CUSTOMER_EMAIL,
        child.ISSUE_DATE,
        parent.DEPTH + 1
    from
        [Main table] child
        inner join
        iptable parent
        on
            (
                child.CUSTOMER_EMAIL= parent.CUSTOMER_EMAIL
                or
                child.CUSTOMER_IP = parent.CUSTOMER_IP
            )
            and
            child.ISSUE_DATE > parent.ISSUE_DATE
)
select distinct
    CUSTOMER_EMAIL,
    CUSTOMER_IP
from 
    iptable
where
    ROOT_EMAIL ='ejskslsks@gmail.com'
    and
    ISSUE_DATE between '2015-02-23 00:00:00' and '2015-02-23 23:59:59'

我假设您期望给定电子邮件可能有多个 IP - 给定 IP 可能有多个电子邮件。