首页 > 解决方案 > SQL Server 2012 - 在 WHERE 子句下具有两个条件的递归 CTE

问题描述

#1 编辑

我将 WHERE 子句中的 AND 更改为 OR,一切正常。但是我需要在 CTE 的递归部分使用 JOIN,问题又出现了,因为我不能在这里使用 OUTER JOIN。因此,我将 JOIN 更改为 OUTER APPLY 并且效果很好。


SQL 小提琴:http ://sqlfiddle.com/#!18/9eecb/81809

我正在尝试实现一个递归 CTE,它接收两个年龄并递增这些年龄,直到它们都等于 120。问题是当我尝试将 WHERE 子句添加到递归部分时,谓词被完全忽略:

;with age_cte as (
    select
        26 as wife_age,
        28 as husband_age

    union all

    select
        age_cte.wife_age + 1,
        age_cte.husband_age + 1

    from age_cte

    where wife_age < 120 and husband_age < 120

) select * from age_cte;

一旦其中一个年龄达到 120,CT​​E 就会停止。在这个例子中,当丈夫年龄等于 120 时,妻子的年龄是 118,然后计算停止。

我知道数据库遵循查询的逻辑。我的问题是我应该怎么做才能将正确的逻辑应用于该 CTE,即当一个年龄超过 120 直到另一个年龄达到 120 时返回 NULL?

Example:

.     .
.     .
.     .
118   120
119   NULL
120   NULL

我尝试使用具有两个锚点和两个递归部分的 CTE,如下面的文档示例(“H. Using multiple anchor and recursive members”):

create table age (
    wife_age int,
    husband_age int
);
insert into age values(26, 28);
;with age_cte as (
    -- first anchor
    select
        wife_age
    from age
    union
    -- second anchor
    select
        husband_age
    from age

    union all

    select
        age_cte.wife_age + 1
    from age_cte

    where wife_age < 120

    union all
    --
    select
        age_cte.husband_age + 1
    from age_cte

    where husband_age < 120

) select * from age_cte;

我遗漏了一些东西,因为它在第二个递归查询中为“husband_age”提供了“无效的列名”。

我也试过这个查询

;with age_cte as (
    select
        26 as wife_age,
        28 as husband_age

    union all

    select
        case when age_cte.wife_age + 1 > 120 then null else age_cte.wife_age + 1 end,
        case when age_cte.husband_age + 1 > 120 then null else age_cte.husband_age + 1 end

    from age_cte

    where 120 >= case 
                     when age_cte.wife_age + 1 < age_cte.husband_age + 1 then
                         age_cte.wife_age + 1
                     else
                         age_cte.husband_age + 1
                 end


) select * from age_cte;

但要么它给出一个无限循环,要么年龄达到 119 永远不会达到 120。

标签: sqlsql-servertsqlcommon-table-expressionrecursive-query

解决方案


这应该做你想要的:

with age_cte as (
    select 26 as wife_age, 28 as husband_age
    union all
    select
        case when wife_age < 120 then wife_age + 1 end,
        case when husband_age < 120 then husband_age + 1 end
    from age_cte
    where wife_age < 120 or husband_age < 120

) 
select * from age_cte;

那是:

  • 你想orwhere递归查询的子句中而不是and,所以查询会一直持续到两个年龄都达到 120

  • 您可以在年龄超过 120 岁时使用条件逻辑select来生成snull

DB Fiddle 上的演示

妻子年龄 | 丈夫年龄
--------: | ----------:
      26 | 28
      27 | 29
      28 | 30
      29 | 31
...
     116 | 118
     117 | 119
     118 | 120
     119 |        
     120 |        无效的

推荐阅读