Доступ к текущей строке (не предыдущей строке) в рекурсивной части рекурсивного общего табличного выражения (CTE) - PullRequest
0 голосов
/ 23 апреля 2020

DB FIDDLE

SAMPLE CODE

create table lifetable (
    age int,
    qx decimal(8, 6)
);

insert into
    lifetable
values (18, 0.000066),
    (19, 0.000130),
    (20, 0.000244),
    (21, 0.000256),
    (22, 0.000289),
    (23, 0.000301),
    (24, 0.000377),
    (25, 0.000406),
    (26, 0.000431),
    (27, 0.000442),
    (28, 0.000456),
    (29, 0.000476),
    (30, 0.000566);


create table people (
    age int,
    name varchar(10)
);

insert into
    people
values (18, 'George'),
    (23, 'William'),
    (27, 'Kate');

;with cte as (
    select
        name,
        p.age,
        qx,
        cast(iif(p.age > 30, 0, 1) as decimal(10, 7)) as pxaa,
        cast(iif(p.age > 30, 0, 1) as decimal(10, 7)) as tpxaa
    from people as p
    left join lifetable as lt
        on p.age = lt.age

    union all

    select
        name,
        cte.age + 1,
        lt.qx,
        cast(pxaa * lt.qx as decimal(10, 7)), -- as pxaa
        /****
        ** I need the current value of pxaa and the previous value of tpxaa to calculate
        ** the sebsequent values of tpxaa
        **/
        cast(lead(pxaa) over (partition by name order by cte.age asc) * tpxaa as decimal(10, 7)) -- as tpxaa
    from cte
    join lifetable as lt
        on cte.age + 1 = lt.age

    where cte.age < 30
) select * from cte order by name, age option (maxrecursion 0);

В этом конкретном случае столбец tpxaa начинается с 1 или 0 в первой строке и во второй строке для значений tpxaa рассчитываются с использованием его предыдущего значения (предыдущая строка в столбце tpxaa) и текущего значения (текущая строка в столбце pxaa) для pxaa, который является еще одним столбцом, значения которого также рассчитываются.

I не знаю, что делать, но использовать рекурсивный CTE. Но рекурсивный CTE имеет доступ только к предыдущему ряду. Это хорошо, так как я могу получить предыдущую строку tpxaa, но я также получаю предыдущую строку pxaa, что является нежелательным поведением.

Я пытался использовать OUTER APPLY в столбце pxaa, но SQL Server Management Studio (SSMS) выдает мне сообщение

Повторный член CTE имеет несколько рекурсивных ссылок

LAG и LEAD будут иметь значения NULL. Возможно, потому что значения pxaa также рассчитываются

CROSS APPLY даст мне декартово произведение, которое мне не нужно.

В Excel ссылки могут быть визуализированы:

enter image description here

Как вычислить столбец, значения которого зависят от его собственной предыдущей строки и текущей строки другого вычисляемого столбца в SQL Сервер?

1 Ответ

1 голос
/ 23 апреля 2020

отказ от ответственности

На самом деле я не очень хорош в рекурсивных CTE. Я не думаю, что этот код является полностью правильным для вас, но я думаю, что он может дать вам представление о том, что я думаю, вам нужно сделать:

;with cte as (
    select
        name,
        p.age,
        qx,
        cast(iif(p.age > 30, 0, 1) as decimal(10, 7)) as pxaa,
        cast(iif(p.age > 30, 0, 1) as decimal(10, 7)) as tpxaa,
        cast (1 as decimal(10, 7)) as previoustpxaa -- I'm not sure what you want for the initial "previous" value of tpxaa since there is no such thing
    from people as p
    left join lifetable as lt
        on p.age = lt.age

    union all

    select
        name,
        cte.age + 1,
        lt.qx,
        cast(pxaa * lt.qx as decimal(10, 7)) as pxaa,
        cast(pxaa * previoustpxaa as decimal(10, 7)) as tpxaa, -- not sure if this should be pxaa * lt.qx * previoustpxaa or something else
        tpxaa as previoustpxaa -- here is where you record the current as the previous
    from cte
    join lifetable as lt
        on cte.age + 1 = lt.age

    where cte.age < 30
) select * from cte order by name, age option (maxrecursion 0);
...