Tsql 如何使今年的开盘价比去年的开盘价有条件?

Tsql 如何使今年的开盘价比去年的开盘价有条件?,tsql,Tsql,我有如下数据表,需要使用t-sql生成 Year | Id | Entitle | Use | Max ----------------------------------- 2016 | 0001 | 15 | 5 | 20 2017 | 0001 | 15 | 2 | 20 2018 | 0001 | 15 | 4 | 20 我需要获得每年的开始和结束,今年的开始将是去年(开始+授权-使用),但不能超过最大值,如果超过最大值,则“最大值

我有如下数据表,需要使用t-sql生成

Year | Id    | Entitle | Use | Max
-----------------------------------
2016 | 0001  | 15      | 5   | 20
2017 | 0001  | 15      | 2   | 20
2018 | 0001  | 15      | 4   | 20
我需要获得每年的开始和结束,今年的开始将是去年(开始+授权-使用),但不能超过最大值,如果超过最大值,则“最大值”将是开始

这是我所期望的结果

year | Id   | Opening | Entitle | Use | Max | Closing
-----------------------------------------------------
2016 | 0001 | 0       | 15      | 5   | 20  | 10
2017 | 0001 | 10      | 15      | 2   | 20  | 23
2018 | 0001 | 20      | 15      | 4   | 20  | 31

简单的SQL在这里是不够的。您需要遍历每一行,并根据上一年计算收盘价和开盘价

我们的想法是在每一行中循环。存储结果。将结果添加到临时表中

我在这里给你编了密码。请注意,我已经使用SSMS来实现它

 DECLARE @TempTable table (_ID varchar(255),Year int,Opening int, Entitle int,Used int,Max int, Closing int)

DECLARE @idColumn INT
DECLARE @ID varchar(255)
DECLARE @entitle INT 
DECLARE @used INT
DECLARE @max INT
DECLARE @opening INT
DECLARE @closing INT
DECLARE @year INT
SELECT @idColumn = min( Id ) FROM MyTable

WHILE @idColumn is not null
BEGIN

SET @year =  (SELECT Year FROM MyTable WHERE Id = @idColumn)
SET @ID =  (SELECT [_ID] FROM MyTable WHERE Id = @idColumn)
IF @idColumn = 1
 BEGIN
    SET @entitle =  (SELECT Entitle FROM MyTable WHERE Id = @idColumn);
    SET @used =  (SELECT Used FROM MyTable WHERE Id = @idColumn);
    SET @opening = 0;
    SET @closing = @opening + @entitle - @used;
    SET @max =  (SELECT Max FROM MyTable WHERE Id = @idColumn);
 END
 ELSE
  BEGIN
    SET @opening = @opening + @entitle - @used;
    IF @opening > @max
     BEGIN
       SET @opening = @max;
     END
    SET @entitle =  (SELECT Entitle FROM MyTable WHERE Id = @idColumn);
    SET @used =  (SELECT Used FROM MyTable WHERE Id = @idColumn);
    SET @max =  (SELECT Max FROM MyTable WHERE Id = @idColumn);
    SET @closing = @opening + @entitle - @used;
  END

INSERT INTO @TempTable (_ID , Year , Opening , Entitle , Used ,Max , Closing )
VALUES (@ID, @year, @opening, @entitle, @used, @max, @closing);
SELECT @idColumn = min( Id ) FROM MyTable WHERE Id > @idColumn
END

SELECT * FROM @TempTable

这里还有另一个选项,递归CTE将使您达到目的

DECLARE @TestData TABLE
    (
        [Year] INT
      , [Id] NVARCHAR(10)
      , [Entitle] INT
      , [Use] INT
      , [Max] INT
    );

INSERT INTO @TestData (
                          [Year]
                        , [Id]
                        , [Entitle]
                        , [Use]
                        , [Max]
                      )
VALUES ( 2016, '0001', 15, 5, 20 )
     , ( 2017, '0001', 15, 2, 20 )
     , ( 2018, '0001', 15, 4, 20 );

INSERT INTO @TestData (
                          [Year]
                        , [Id]
                        , [Entitle]
                        , [Use]
                        , [Max]
                      )
VALUES ( 2015, '0002', 20, 7, 20 )
     , ( 2016, '0002', 20, 7, 20 )
     , ( 2017, '0002', 20, 4, 20 )
     , ( 2018, '0002', 20, 13, 20 );


WITH [cte]
AS ( SELECT      [a].[Year]
               , [a].[Id]
               , 0 AS [Opening]
               , [a].[Entitle]
               , [a].[Use]
               , [a].[Entitle] - [a].[Use] AS [Closing]
     FROM        @TestData [a]
     --Cross apply here to get our first record, earliest year for each Id for our anchor
     CROSS APPLY (
                     SELECT   [aa].[Id]
                            , MIN([aa].[Year]) AS [Year]
                     FROM     @TestData [aa]
                     WHERE    [aa].[Id] = [a].[Id]
                     GROUP BY [aa].[Id]
                 ) [aaa]
     WHERE       [a].[Year] = [aaa].[Year]
                 AND [a].[Id] = [aaa].[Id]
     UNION ALL
     SELECT     [c].[Year]
              , [c].[Id]
              , CASE WHEN [b].[Closing] > [c].[Max] THEN [c].[Max]
                     ELSE [b].[Closing]
                END
              , [c].[Entitle]
              , [c].[Use]
              , CASE WHEN [b].[Closing] > [c].[Max] THEN [c].[Max]
                     ELSE [b].[Closing]
                END + [c].[Entitle] - [c].[Use] AS [Closing]
     FROM       [cte] [b]
     INNER JOIN @TestData [c]
         ON [c].[Id] = [b].[Id]
            AND [c].[Year] = [b].[Year] + 1 )
SELECT   *
FROM     [cte]
ORDER BY [cte].[Id]
       , [cte].[Year];

你可以发布一些你试图得到预期结果的代码示例吗?请编辑你的问题。您如何计算您的
结账
?由于您没有上一年的信息,如何计算2016年的期初?问题是,期初取自去年的收盘价,但不能超过最大值,今年的结帐也将包括今年的结帐。我尝试使用这个左外联接选择TY.*从数据TY左外联接数据LY ON TY.ID=LY.ID和TY.year-1=LY.year,但我无法计算如何获得第一个结帐来计算结帐,如果OP的数据在
ID
列中的每一行都有值
0001
这行吗?提示:
选择@authentice=authentice,@used=used。。。来自MyTable,其中Id=@idColumn。我使用的id列是MyTable的标识。我做了一些更改,现在您有了所要求的_ID列(所有值都相同),感谢Alex Leo为我的问题提供了解决方案,但我认为Tim的解决方案更好,更容易集成到我的项目中。@AlexChea嘿,没问题,至少您有多个解决方案可供选择:-)