【问题标题】:Need to call table function recursively需要递归调用表函数
【发布时间】:2017-06-01 14:40:50
【问题描述】:

我使用的是 SQL Server 2014。我有一个表函数,它接受 2 个参数并返回 2 列。为了简单起见,我们调用函数Get_GroupNumber。

Get_GroupNumber('Smith', '123-456-789')

这将返回 2 列。再次保持简单,假设它是 Reason1 和 Reason2。

Reason1 = '111-222-333'
Reason2 = '555'666'777'

我需要将返回的 Reason1 传递回Get_GroupNumber,并继续这样做,直到它在 Reason1 中返回 NULL,在 Reason2 中也返回 NULL。

所以,第二次调用看起来像这样:

Get_GroupNumber('Smith','111-222-333')

【问题讨论】:

  • 1.该函数是否返回null? 2. 为什么不能使用While 循环?警告一下,这听起来也可能是一个无限循环。
  • 我无法编辑函数本身。是的,该函数可以返回 NULL。虽然 Loop 听起来不错,但我会尝试查找如何做到这一点(抱歉,SQL 编程新手)
  • 好的。我说的是调用函数的存储过程(如果有的话)。在里面放一个循环。
  • 是的,我会尝试为此创建一个 SP。谢谢
  • 刚刚用while循环也做了,我会为后代发布答案

标签: sql sql-server sql-server-2014


【解决方案1】:

如果您不想使用迭代方法(例如,使用 while 循环),则递归 CTE 可以完成这项工作。您可以阅读有关递归 CTE 的更多信息 here,或查看以下示例:

-- Here's a "dummy" function that has some hard-coded return values for illustrative
-- purposes. It will return ('111-222-333', '555-666-777') when it gets 123-456-789
-- as its second parameter, ('999-999-999', '000-000-000') when it gets 111-222-333
-- as its second parameter, and (null, null) otherwise.
create function Get_GroupNumber
(   
    @Param1 varchar(32),
    @Param2 varchar(32)
)
returns table
as
return 
(
    select
        Reason1 = case @Param2 when '123-456-789' then '111-222-333' when '111-222-333' then '999-999-999' else null end,
        Reason2 = case @Param2 when '123-456-789' then '555-666-777' when '111-222-333' then '000-000-000' else null end
);
go

-- The sample inputs from your question.
declare @Param1 varchar(32) = 'Smith';
declare @Param2 varchar(32) = '123-456-789';

-- And finally, the good stuff:
with GroupNumberCTE as
(
    -- Base case: pass the original parameters, get the results from the function, and
    -- create a new field called "Call #" that will illustrate the order in which the
    -- various calls to Get_GroupNumber were made. (This field is purely informational;
    -- you can remove it if you don't want it.)
    select 
        [Call #] = 1,
        Reason1, 
        Reason2 
    from 
        Get_GroupNumber(@Param1, @Param2)

    union all

    -- Recursive case: if the previous call returned a non-null value in either field,
    -- invoke the function again with the original @Param1 and the Reason1 from the
    -- previous call. 
    select
        [Call #] = [Previous].[Call #] + 1,
        [Next].Reason1,
        [Next].Reason2
    from
        GroupNumberCTE [Previous]
        cross apply Get_GroupNumber(@Param1, [Previous].Reason1) [Next]
    where
        [Previous].Reason1 is not null or
        [Previous].Reason2 is not null
)
select * from GroupNumberCTE;

结果集:

Call #   Reason1       Reason2
----------------------------------
1        111-222-333   555-666-777
2        999-999-999   000-000-000
3        NULL          NULL

我应该指出这里有一个危险:我的 CTE 本身的结构中没有任何东西可以保证递归最终会结束。因此,您必须确保对于任何可行的初始输入集,您的Get_GroupNumber 实现最终将返回两个空值。只要是这样,这种方法应该行得通。

【讨论】:

    【解决方案2】:
    Using While Loop
    
    DECLARE @key varchar(max);
    DECLARE @retVal varchar(max);
    SET @key = '123-456-789'
    While @Key is not null
    BEGIN
        set @retval = @key
        SET @key = (SELECT Return2 from [dbo].[Get_GroupNumber]('Smith',@key))
    END;
    
    print @retVal
    

    我知道我只是在这里使用 Return2 列的返回值来测试

    【讨论】:

      猜你喜欢
      • 2020-11-22
      • 2018-06-04
      • 1970-01-01
      • 2021-12-16
      • 2018-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-17
      相关资源
      最近更新 更多