繁体   English   中英

SQL递归查询作为子查询

[英]SQL Recursive query as subquery

我在这里使用一个 SQL 数据库,其中包含一个名为CONTACT的表,我在其中存储与联系人相关的数据及其来源,以便我可以跟踪它的来源。 CONTACT表中的一个特定字段称为CONTACT_SOURCE而另一个字段CONTACT_SOURCE_CONTACT_ID是在CONTACT_ID上与同一个表的自CONTACT_ID 我试图做的是显示CONTACT数据,包括当我加入数据库中的其他表(如QUOTEORDER等)时它的来源。

然而,我试图处理这里的递归场景,而不是标准的SELF-JOIN 例如,我的字段CONTACT_SOURCE_CONTACT_ID是我将另一个联系人的CONTACT_ID存储在同一个CONTACT表中的位置,该表将该联系人口头推荐给我的公司。 我在这里尝试做的是使用此CONTACT_SOURCE_CONTACT_ID字段递归跟踪联系人,以显示将他们推荐给我的此联系人的来源作为他们的来源。 例如,如果约翰在社交媒体上找到我并告诉安妮,然后安妮告诉鲍勃谁最终提交了报价,我想将鲍勃与约翰的来源(通过安妮)相关联,因此将社交媒体显示为他的来源,因此是报价单。

WITH CTE
AS (
/*Anchor query that returns CONTACT records without a corresponding CONTACT_SOURCE_CONTACT_ID record*/
SELECT C1.CONTACT_ID, C1.CONTACT_SOURCE
FROM CONTACT AS C1
WHERE CONTACT_SOURCE_CONTACT_ID IS NULL

UNION ALL

/*Recursive query that returns CONTACT records with a corresponding CONTACT_SOURCE_CONTACT_ID record*/
SELECT C2.CONTACT_ID, CTE.CONTACT_SOURCE
FROM CONTACT AS C2
INNER JOIN CTE ON CTE.CONTACT_ID = C2.CONTACT_SOURCE_CONTACT_ID
WHERE C2.CONTACT_SOURCE_CONTACT_ID IS NOT NULL)

SELECT QUOTE.QUOTE_ID, CONTACT.CONTACT_ID, CONTACT.CONTACT_NAME, CTE.CONTACT_SOURCE
FROM CTE
INNER JOIN CONTACT ON CTE.CONTACT_ID = CONTACT.CONTACT_ID
INNER JOIN QUOTE ON QUOTE.QUOTE_CONTACT_ID = CONTACT.CONTACT_ID
ORDER BY CTE.CONTACT_ID;

我已经构建了一个SQL Fiddle 示例,该示例使用测试数据以及我为完成此操作而构建的递归 SQL 查询来演示这一点,并且效果很好!

这一切都是有道理的,但我只是好奇我是否正确执行此操作,以及当我将此递归查询用作子查询时这是否有效。 我不应该在递归查询中引用QUOTE_CONTACT_ID字段吗? 我觉得我正在检查整个CONTACT表中的所有递归关系,而不仅仅是作为SELECT * FROM dbo_QUOTE INNER JOIN dbo_CONTACT ON CONTACT_ID = QUOTE_CONTACT_ID返回的CONTACT记录。 假设我有 2,000 条QUOTE记录,但有 12,000 条CONTACT记录。 当我只想查看QUOTE记录时,我只想对在QUOTE表中具有相应记录的CONTACT记录运行递归查询。

这有意义吗? 在此先感谢您的任何建议或提示!

可以使用递归 CTE 处理分层数据(您在这里拥有的是分层数据),但这并不意味着您应该这样做。

Microsoft 专门提供了处理分层数据的功能——它是专门为这些场景设计和优化的。 因此,它最适合解决此类问题。

更多信息: https : //msdn.microsoft.com/en-us/library/bb677173.aspx

这可能对某些人有所帮助.. 您可以在 CTE 中获取查询所需的所有信息..

WITH CTE AS (
    SELECT
        Q.QUOTE_ID,
        C.CONTACT_ID,
        C.CONTACT_NAME,
        C.CONTACT_SOURCE
    FROM
        QUOTE AS Q
        INNER JOIN CONTACT AS C ON Q.QUOTE_CONTACT_ID = C.CONTACT_ID
    WHERE
        CONTACT_SOURCE_CONTACT_ID IS NULL
    UNION ALL
    SELECT
        Q.QUOTE_ID,
        C.CONTACT_ID,
        C.CONTACT_NAME,
        CTE.CONTACT_SOURCE
    FROM
        QUOTE AS Q
        INNER JOIN CONTACT AS C ON Q.QUOTE_CONTACT_ID = C.CONTACT_ID
        INNER JOIN CTE ON CTE.CONTACT_ID = C.CONTACT_SOURCE_CONTACT_ID
    WHERE
        C.CONTACT_SOURCE_CONTACT_ID IS NOT NULL
)
SELECT
    *
FROM
    CTE
ORDER BY
    CTE.CONTACT_ID;

老实说,在查看了查询计划后,我会坚持使用您拥有的内容.. 只需将 contact_name 添加到您的 cte 查询中,这样您就不必再次加入 Contact ..

WITH CTE AS (
    SELECT
        C1.CONTACT_ID,
        C1.CONTACT_SOURCE,
        C1.CONTACT_NAME
    FROM
        CONTACT AS C1
    WHERE
        CONTACT_SOURCE_CONTACT_ID IS NULL
    UNION ALL
    SELECT
        C2.CONTACT_ID,
        CTE.CONTACT_SOURCE,
        C2.CONTACT_NAME
    FROM
        CONTACT AS C2
        INNER JOIN CTE ON CTE.CONTACT_ID = C2.CONTACT_SOURCE_CONTACT_ID
    WHERE
        C2.CONTACT_SOURCE_CONTACT_ID IS NOT NULL
)
SELECT
    QUOTE.QUOTE_ID,
    CTE.CONTACT_ID,
    CTE.CONTACT_NAME,
    CTE.CONTACT_SOURCE
FROM
    CTE
    INNER JOIN QUOTE ON QUOTE.QUOTE_CONTACT_ID = CTE.CONTACT_ID
ORDER BY
    CTE.CONTACT_ID;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM