我正在使用一个SQL数据库,其中包含一个名为CONTACT
的表,我在其中存储与联系人及其来源相关的数据,以便我可以跟踪它的来源。 CONTACT
表中的一个特定字段称为CONTACT_SOURCE
,而另一个字段CONTACT_SOURCE_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 example,它使用测试数据以及我为实现此目的而构建的递归SQL查询来演示这一点,并且效果很好!
这一切都有道理,但我只是好奇我是否正确地这样做,并且当我使用这个递归查询作为子查询时这是有效的。我不应该在递归查询中引用QUOTE_CONTACT_ID
字段吗?我觉得我正在检查整个CONTACT
表中的所有递归关系,而不仅仅是因CONTACT
而返回的SELECT * FROM dbo_QUOTE INNER JOIN dbo_CONTACT ON CONTACT_ID = QUOTE_CONTACT_ID
记录。假设我有2,000条QUOTE
条记录但有12,000条CONTACT
条记录。当我只想查看QUOTE
条记录时,我只希望递归查询为CONTACT
表中具有相应记录的QUOTE
记录运行。
这有意义吗?提前感谢任何建议或提示!
答案 0 :(得分:1)
可以使用递归CTE处理分层数据(这里有分层数据),但这并不意味着你应该这样做。
Microsoft专门提供了处理分层数据的功能 - 它专门针对这些场景进行了设计和优化。因此,它最适合这类问题。
更多信息: https://msdn.microsoft.com/en-us/library/bb677173.aspx
答案 1 :(得分:0)
这可能对某些人有所帮助..您可以在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查询中,这样您就不必再次加入联系人了..
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;