【问题标题】:Understanding SQL Recursion了解 SQL 递归
【发布时间】:2015-06-04 16:25:31
【问题描述】:

我有以下代码

      SELECT 
            Customer,
            booking,
            [date],
            Parent_Booking,
            0 AS change_number
            FROM bookings

假设我有一个网站,客户可以在该网站上预订房晚。对于在网站上进行的每个预订,都会创建一个预订号。

例子:

我的 DB2 表中的当前行:

Customer    booking#      date      Parent_Booking
1           11111         1.01.15   NULL

现在是重要的部分。如果客户更改他的预订,与他的原始预订相关的预订号将被冻结,并会创建一个新的预订号。假设客户更改了 3 次预订。我表中的行如下所示:

Customer    booking#      date      Parent_Booking
1           11111         1.01.15   NULL
1           22222         5.01.15   11111          -----> First Change
1           33333         6.01.15   22222          -----> Second Change
1           44444         10.01.15  33333          -----> Third Change

现在如果我运行上面的代码,我只会得到前两行:

Customer    booking#      date      Parent_Booking
1           11111         1.01.15   NULL
1           22222         5.01.15   11111          -----> First Change

我想获取所有行,这意味着我想使用递归并获取父母的所有父母,直到没有父母为止。如何修改我的主查询以实现此目的?

我认为这部分需要发生:

ON        AL.[Parent Reservation No_]=DB2.[B_KEY] 

我想继续加入,直到[父母预订号] = NULL

【问题讨论】:

  • 需要用到递归查询:technet.microsoft.com/en-us/library/…
  • @Evaldas:我知道如何使用CTE,但是在这个例子中如何使用i来帮助我呢?你能给我更多信息吗
  • 您需要两个单独的查询才能获得结果。一个获取所有ID,另一个进行加入。现在想办法。

标签: sql sql-server recursion


【解决方案1】:

由于您使用的是 T-SQL,并且您的表结构为 adjacency list,因此您正在寻找的解决方案是 Recursive Common Table Expression:

WITH cte AS (
  SELECT 
    Customer,
    booking,
    [date],
    Parent_Booking,
    0 AS change_number
  FROM bookings
  WHERE Parent_Booking IS NULL

  UNION ALL 

  SELECT
    b2.Customer,
    b2.booking,
    b2.[date],
    b2.Parent_Booking,
    cte.change_number + 1 AS change_number
  FROM bookings b2
  INNER JOIN cte ON b2.Parent_Booking = cte.booking
)

SELECT * FROM  cte

Here's a SQLFiddle

表达式的第一部分选择“基本”行,即那些没有父对象的行,然后表达式的第二部分递归地连接到结果集,直到没有更多的结果要连接,或者直到 100 次递归到达,以先到者为准。

change_number 列是我添加的,用于显示客户更改预订的次数,但它也说明了递归的工作原理。 change_number = 0 的行来自第一个递归,change_number = 0 or 1 的行来自第二个递归,依此类推。当您在集合中递归时,能够构建像这样的自定义列对于排序或聚合数据非常有用,我想包含一个此功能的简单示例。

【讨论】:

  • @Paul:你能告诉我你所说的 0 AS change_number 是什么意思吗 :)?
  • 这只是一种查看客户更改预订次数的方法。在这个例子中,这也是说明递归深度的好方法。 change_number = 0 的行是第一次递归的结果集,change_number = 0 或 1 的行是第二次递归的结果集,依此类推。您可以看到每个递归是如何建立在最后一个之上的。我会将此信息添加到答案中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多