递归cte与2个表的值

时间:2018-05-02 07:27:42

标签: sql-server tsql recursion

我需要一些帮助。

我想创建一个递归查询,其中包含来自锚表的值,再乘以另一个表中的系数。

让我更明确一点:

表格结构和填充:

create table T
(
  Site varchar(10) primary key,
  Price money,
  Year int
);

create table B
( Site varchar(10),
  Coeff float,
  Year int
);

insert into T values /* Each Site appears only once here */
('A', 125.10, 2003),
('B', 78.10, 2002),
('C', 23.34, 2001)

insert into B values /* Each (Site,Year) appears only once here */
('A', 12, 2003),
('A', 0.111, 2004),
('B', 0.322, 2002),
('B', 0.333, 2003),
('C', 0.555, 2001),
('C', 0.666, 2002)

我的递归公式为:  价格(n)=价格(n-1)* Coeff(n-1) (其中n是年份)

这是我的最后一次尝试:

;WITH cte
AS (SELECT T.Site, T.Year, T.Price as RootPrice FROM T
UNION ALL 
SELECT T.Site, T.Year, CAST(cte.RootPrice * B.Coeff AS MONEY) AS PriceYear

FROM T INNER JOIN cte ON T.Site = cte.Site AND T.Year = cte.Year INNER JOIN B ON cte.Year = B.Year AND cte.Site = B.Site)    
SELECT * FROM cte

这个cte无休止地运行。我错过了什么?

修改:

需要输出:

Site  | Price     | Year 
---------------------------
 A    | 1501.2   | 2003
 A    | 166.78   | 2004
 B    | 25.15    | 2002
 B    | 8.37     | 2003
 C    | 12.95    | 2001
 C    | 8.63     | 2002

1 个答案:

答案 0 :(得分:2)

这会产生您想要的输出:

;WITH CTE AS
(
    SELECT
        Site = T.Site,
        Year = T.Year,
        Price = CONVERT(MONEY, T.Price * B.Coeff)
    FROM
        T AS T
        INNER JOIN B AS B ON 
            T.Site = B.Site AND
            T.Year = B.Year

    UNION ALL

    SELECT
        Site = C.Site,
        Year = C.Year + 1,
        Price = CONVERT(MONEY, C.Price * B.Coeff)
    FROM
        CTE AS C
        INNER JOIN B AS B ON 
            C.Site = B.Site AND
            C.Year + 1 = B.Year
)
SELECT
    *
FROM
    CTE AS C
ORDER BY
    C.Site,
    C.Year

您的解决方案的问题是锚点不是以正确的价格开头,您应该将价格与锚点上的coeff相乘。请记住,锚是第一组生成的CTE,它包含在其中。

所以你的主播:

SELECT 
    T.Site, 
    T.Year, 
    T.Price as RootPrice 
FROM 
    T

应该从当年的正确价格开始:

SELECT
    Site = T.Site,
    Year = T.Year,
    Price = CONVERT(MONEY, T.Price * B.Coeff)
FROM
    T AS T
    INNER JOIN B AS B ON 
        T.Site = B.Site AND
        T.Year = B.Year

并删除递归集上的T引用,因为您不再需要它了。

如果您还想查看根价格,可以使用递归连接表达式篡改一下:

;WITH CTE AS
(
    SELECT
        Site = T.Site,
        Year = T.Year,
        Price = T.Price,
        IsRoot = 1
    FROM
        #T AS T


    UNION ALL

    SELECT
        Site = C.Site,
        Year = CASE WHEN C.IsRoot = 1 THEN C.Year ELSE C.Year + 1 END,
        Price = CONVERT(MONEY, C.Price * B.Coeff),
        IsRoot = 0
    FROM
        CTE AS C
        INNER JOIN #B AS B ON C.Site = B.Site
    WHERE
        (C.IsRoot = 1 AND C.Year = B.Year) OR
        (C.IsRoot = 0 AND C.Year + 1 = B.Year)
)
SELECT
    *
FROM
    CTE AS C
ORDER BY
    C.Site,
    C.Year,
    C.IsRoot DESC

/*
Results:

Site       Year        Price                 IsRoot
---------- ----------- --------------------- -----------
A          2003        125,10                1
A          2003        1501,20               0
A          2004        166,6332              0
B          2002        78,10                 1
B          2002        25,1482               0
B          2003        8,3744                0
C          2001        23,34                 1
C          2001        12,9537               0
C          2002        8,6272                0

*/