SQL Server中的递归查询

38

我有一个具有以下结构的表格

表格名称: matches

Table name: matches

这个表格基本上存储了哪个产品与哪个产品相匹配。我需要处理这个表格并像下面这样存储在一个组表中。

表格名称: groups

enter image description here

group_ID 存储了形成一个组的Product_IDS中的MIN Product_ID。举个例子,假设

如果A与B匹配,并且B与C匹配,则应将三行以(A, A), (A, B), (A, C)格式添加到组表中

我尝试查看相关的子查询和CTE,但无法实现这个功能。

我需要在SQL中完成所有这些操作。

感谢您的帮助。


2
你可以使用递归公共表达式 - Tim Schmelter
递归CTE似乎是在SQL中实现递归处理的唯一方法,但我并没有真正理解如何解决我的问题。你能否给出任何接近我需求的示例。感谢帮助。 - Ankit
其实不是,我只是遍历所有产品,执行匹配算法,然后将匹配结果保存在“匹配”表中。我认为没有根节点这样的东西。 - Ankit
3个回答

71

试一下这个:

;WITH CTE
AS
(
    SELECT DISTINCT
        M1.Product_ID Group_ID,
        M1.Product_ID
    FROM matches M1
        LEFT JOIN matches M2
            ON M1.Product_Id = M2.matching_Product_Id
    WHERE M2.matching_Product_Id IS NULL
    UNION ALL
    SELECT
        C.Group_ID,
        M.matching_Product_Id
    FROM CTE C
        JOIN matches M
            ON C.Product_ID = M.Product_ID
)
SELECT * FROM CTE ORDER BY Group_ID

您可以使用OPTION(MAXRECURSION n)来控制递归深度。

SQL FIDDLE DEMO


当我使用我的实际数据进行尝试时,它没有返回任何结果。http://sqlfiddle.com/#!3/aff16/1 - Ankit
1
@Ankit 我认为你应该避免像(1,2)和(2,1)这样的一对。 - Hamlet Hakobyan
谢谢,我按照您说的做了,可以在这里看到:http://sqlfiddle.com/#!3/d41d8/8042。使用这个数据的查询正常工作。但是,如果在最后添加(2294543, 1802989),它就会出错并开始给出“达到最大递归级别”的错误。您有什么想法为什么会这样?什么样的数据会导致这种情况? - Ankit
如果你加上 (2294543, 1802989),你会得到无限递归,因为这对数是 (1802989, 2294543)。请参考我上面的评论。 - Hamlet Hakobyan
好的,我明白了出了什么问题。如果数据是像A匹配B和C,而C匹配D,那么它就可以工作并生成组(A,B,C,D)。但是,如果数据是像A匹配B和C,而D匹配C,那么它就会生成两个组(ABC)和(DC)。看起来它只能单向工作,而不能双向工作。 - Ankit
当我尝试从链接运行SQL Fiddle演示时,出现“String index out of range: 33”错误。 - Ryan Gates

2
最初的回答:
递归级别示例:

enter image description here

DECLARE @VALUE_CODE AS VARCHAR(5);

--SET @VALUE_CODE = 'A' -- Specify a level

WITH ViewValue AS
(
    SELECT ValueCode
    , ValueDesc
    , PrecedingValueCode
    FROM ValuesTable
    WHERE PrecedingValueCode IS NULL
    UNION ALL
    SELECT A.ValueCode
    , A.ValueDesc
    , A.PrecedingValueCode 
    FROM ValuesTable A
    INNER JOIN ViewValue V ON
        V.ValueCode = A.PrecedingValueCode
)

SELECT ValueCode, ValueDesc, PrecedingValueCode

FROM ViewValue

--WHERE PrecedingValueCode  = @VALUE_CODE -- Specific level

--WHERE PrecedingValueCode  IS NULL -- Root

1
为什么在每个实例之后都注释掉@VALUE_CODE,你还要声明它?此外,这个答案似乎非常特定于您的表格格式,而不是问题中引用的模式。 - PausePause

2

类似这样的内容(未经测试)

with match_groups as (

  select product_id, 
         matching_product_id,
         product_id as group_id
  from matches
  where product_id not in (select matching_product_id from matches)

  union all

  select m.product_id, m.matching_product_id, p.group_id
  from matches m
    join match_groups p on m.product_id = p.matching_product_id
)
select group_id, product_id
from match_groups
order by group_id;

它没有返回正确的结果[http://sqlfiddle.com/#!3/aff16/6](http://sqlfiddle.com/#!3/aff16/6) - Ankit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接