[英]SQL Recursive query as subquery
我在这里使用一个 SQL 数据库,其中包含一个名为CONTACT
的表,我在其中存储与联系人相关的数据及其来源,以便我可以跟踪它的来源。 CONTACT
表中的一个特定字段称为CONTACT_SOURCE
而另一个字段CONTACT_SOURCE_CONTACT_ID
是在CONTACT_ID
上与同一个表的自CONTACT_ID
。 我试图做的是显示CONTACT
数据,包括当我加入数据库中的其他表(如QUOTE
、 ORDER
等)时它的来源。
然而,我试图处理这里的递归场景,而不是标准的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.