Sql 需要帮助执行以下计算吗

Sql 需要帮助执行以下计算吗,sql,sql-server,oracle,Sql,Sql Server,Oracle,我有一个特定的值,比如说10,作为我计算的基础。现在,与值10对应的第一个期间的增长为5。我想要的结果是10*1+5/100,基本上是增长的基数*1+%。第一个期间的结果值将成为下一个期间的新基数。假设下一个增长是6,下一个时期的结果是101+5/100*1+6/100。这基本上是运行乘法,可以通过多种方式实现。现在请有人提出实现这一计算的最终最佳方法 10 , 5 -> 10 1 + 5/100 = 10.50 10.50 , 6 -> 10.50 1 + 6/100 = 11

我有一个特定的值,比如说10,作为我计算的基础。现在,与值10对应的第一个期间的增长为5。我想要的结果是10*1+5/100,基本上是增长的基数*1+%。第一个期间的结果值将成为下一个期间的新基数。假设下一个增长是6,下一个时期的结果是101+5/100*1+6/100。这基本上是运行乘法,可以通过多种方式实现。现在请有人提出实现这一计算的最终最佳方法

10 , 5 -> 10 1 + 5/100 = 10.50 10.50 , 6 -> 10.50 1 + 6/100 = 11.1300 11.13、任何值等 我尝试过使用其他数据样本的方法,但基本上是运行乘法

CREATE TABLE #t1
  (
     projection_details_sid INT,
     period_sid             INT,
     growth                 NUMERIC(22, 6)
  )

INSERT INTO #t1
            (projection_details_sid,
             period_sid,
             growth)
VALUES      ( 1,601,2 ),
            ( 1,602,2 ),
            ( 1,603,2 ),
            ( 1,604,1 ),
            ( 1,605,6 ),
            ( 1,606,3 )

SELECT *,
       Exp(Sum(Log(growth))
             OVER (
               PARTITION BY projection_details_sid
               ORDER BY projection_details_sid ROWS UNBOUNDED PRECEDING ))
FROM   #t1 

您可以从下面的查询中获得想法:-

DECLARE @Growth INT = 5
    ,@Base DECIMAL(18,2) = 10.0;

;WITH Test(Base, Growth)
AS
(
    SELECT @Base, @Growth

    UNION ALL

    SELECT CAST(t.Base * (1 + t.Growth/100.0) AS DECIMAL(18,2))  , t.Growth + 1
    FROM Test t
    WHERE t.Base < 600000000
)

SELECT * 
FROM Test
option (maxrecursion 0)

您可以从下面的查询中获得想法:-

DECLARE @Growth INT = 5
    ,@Base DECIMAL(18,2) = 10.0;

;WITH Test(Base, Growth)
AS
(
    SELECT @Base, @Growth

    UNION ALL

    SELECT CAST(t.Base * (1 + t.Growth/100.0) AS DECIMAL(18,2))  , t.Growth + 1
    FROM Test t
    WHERE t.Base < 600000000
)

SELECT * 
FROM Test
option (maxrecursion 0)
尝试递归查询。 下面的示例是针对Oracle的,但它可以很容易地应用于SQL Server

WITH our_recursive_query(projection_details_sid,  period_sid, growth,  base,  our_result)
AS (
    select projection_details_sid,  period_sid, growth, 
           10.0 as base, 
           10 * ( 1 + growth/100) As our_result
    from t1 where period_sid = 601

    UNION ALL

    SELECT a.projection_details_sid,  a.period_sid, a.growth, 
           b.our_result as base, 
           b.our_result * ( 1 + a.growth/100) As our_result
    FROM t1 a
    JOIN our_recursive_query b
    ON a.period_sid = b.period_sid + 1
)
SELECT * FROM our_recursive_query
结果是:

                 PROJECTION_DETAILS_SID PERIOD_SID     GROWTH         BASE   OUR_RESULT
--------------------------------------- ---------- ---------- ------------ ------------
                                      1        601          2  10.00000000  10.20000000
                                      1        602          2  10.20000000  10.40400000
                                      1        603          2  10.40400000  10.61208000
                                      1        604          1  10.61208000  10.71820080
                                      1        605          6  10.71820080  11.36129285
                                      1        606          3  11.36129285  11.70213163
                 PROJECTION_DETAILS_SID PERIOD_SID     GROWTH   MULTIPLIER   OUR_RESULT
--------------------------------------- ---------- ---------- ------------ ------------
                                      1        601          2   1.02000000  10.20000000
                                      1        602          2   1.04040000  10.40400000
                                      1        603          2   1.06120800  10.61208000
                                      1        604          1   1.07182008  10.71820080
                                      1        605          6   1.13612928  11.36129285
                                      1        606          3   1.17021316  11.70213163
我假设period\u sid递增1,因此我使用.period\u sid=b.period\u sid+1作为联接条件。如果在实际数据中不是这样,则需要使用行数分析函数略微修改查询

编辑
@科迪科,谢谢。有没有其他可能达到这个结果 而不是递归cte,因为递归cte具有类似的性能 当然是while循环

对。在Oracle中,您可以创建自己的聚合函数来执行数字链的乘法运算,其方式与内置求和函数的方式类似==>X1+X2+…+Xn,但实际上是X1*X2*…*Xn。 例如:

create or replace TYPE MyCumulativeMultiply_type
AS OBJECT (

cumulativeMultiplyResult NUMBER,

STATIC FUNCTION odciaggregateinitialize(ctx IN OUT MyCumulativeMultiply_type) RETURN NUMBER,

MEMBER FUNCTION odciaggregateiterate(self IN OUT MyCumulativeMultiply_type, your_parameter_to_aggregate IN NUMBER) RETURN NUMBER,

MEMBER FUNCTION odciaggregatemerge(self IN OUT MyCumulativeMultiply_type, ctx2 IN MyCumulativeMultiply_type) RETURN NUMBER,

MEMBER FUNCTION odciaggregateterminate(self IN MyCumulativeMultiply_type, returnvalue OUT NUMBER, flags IN NUMBER) RETURN NUMBER
);
/
CREATE OR REPLACE TYPE BODY MyCumulativeMultiply_type
IS
    STATIC FUNCTION odciaggregateinitialize(ctx IN OUT MyCumulativeMultiply_type)
        RETURN NUMBER
    IS
    BEGIN
          -- instantiate our type, NULL the dummy attribute
        ctx  := MyCumulativeMultiply_type( 1 );
        RETURN odciconst.success;
    END odciaggregateinitialize;

    MEMBER FUNCTION odciaggregateiterate(self IN OUT MyCumulativeMultiply_type, your_parameter_to_aggregate IN NUMBER)
        RETURN NUMBER
    IS
    BEGIN
        self.cumulativeMultiplyResult := self.cumulativeMultiplyResult * your_parameter_to_aggregate; 
        RETURN odciconst.success;
    END odciaggregateiterate;

    MEMBER FUNCTION odciaggregatemerge(self IN OUT MyCumulativeMultiply_type, ctx2 IN MyCumulativeMultiply_type)
        RETURN NUMBER
    IS
    BEGIN
       self.cumulativeMultiplyResult := self.cumulativeMultiplyResult * ctx2.cumulativeMultiplyResult;
        RETURN odciconst.success;
    END odciaggregatemerge;

    MEMBER FUNCTION odciaggregateterminate(self          IN   MyCumulativeMultiply_type,
                                           returnvalue      OUT NUMBER,
                                           flags         IN     NUMBER
                                          )
        RETURN NUMBER
    IS
    BEGIN
        returnvalue := self.cumulativeMultiplyResult;
        RETURN odciconst.success;
    END odciaggregateterminate;
END;
/

CREATE OR REPLACE FUNCTION cumulative_multiply(arg NUMBER)
    RETURN NUMBER
    PARALLEL_ENABLE
    AGGREGATE USING MyCumulativeMultiply_type;
    /
现在一个查询是:

select t1.*
      , cumulative_multiply(  1 + growth/100 ) OVER (order by period_sid ) as multiplier
      , 10 * cumulative_multiply(  1 + growth/100 ) OVER (order by period_sid ) as our_result
from t1;
结果是:

                 PROJECTION_DETAILS_SID PERIOD_SID     GROWTH         BASE   OUR_RESULT
--------------------------------------- ---------- ---------- ------------ ------------
                                      1        601          2  10.00000000  10.20000000
                                      1        602          2  10.20000000  10.40400000
                                      1        603          2  10.40400000  10.61208000
                                      1        604          1  10.61208000  10.71820080
                                      1        605          6  10.71820080  11.36129285
                                      1        606          3  11.36129285  11.70213163
                 PROJECTION_DETAILS_SID PERIOD_SID     GROWTH   MULTIPLIER   OUR_RESULT
--------------------------------------- ---------- ---------- ------------ ------------
                                      1        601          2   1.02000000  10.20000000
                                      1        602          2   1.04040000  10.40400000
                                      1        603          2   1.06120800  10.61208000
                                      1        604          1   1.07182008  10.71820080
                                      1        605          6   1.13612928  11.36129285
                                      1        606          3   1.17021316  11.70213163
不幸的是,我不知道上述方法在SQL Server中是可行的。

尝试递归查询。
WITH our_recursive_query(projection_details_sid,  period_sid, growth,  base,  our_result)
AS (
    select projection_details_sid,  period_sid, growth, 
           10.0 as base, 
           10 * ( 1 + growth/100) As our_result
    from t1 where period_sid = 601

    UNION ALL

    SELECT a.projection_details_sid,  a.period_sid, a.growth, 
           b.our_result as base, 
           b.our_result * ( 1 + a.growth/100) As our_result
    FROM t1 a
    JOIN our_recursive_query b
    ON a.period_sid = b.period_sid + 1
)
SELECT * FROM our_recursive_query
下面的示例是针对Oracle的,但它可以很容易地应用于SQL Server

WITH our_recursive_query(projection_details_sid,  period_sid, growth,  base,  our_result)
AS (
    select projection_details_sid,  period_sid, growth, 
           10.0 as base, 
           10 * ( 1 + growth/100) As our_result
    from t1 where period_sid = 601

    UNION ALL

    SELECT a.projection_details_sid,  a.period_sid, a.growth, 
           b.our_result as base, 
           b.our_result * ( 1 + a.growth/100) As our_result
    FROM t1 a
    JOIN our_recursive_query b
    ON a.period_sid = b.period_sid + 1
)
SELECT * FROM our_recursive_query
结果是:

                 PROJECTION_DETAILS_SID PERIOD_SID     GROWTH         BASE   OUR_RESULT
--------------------------------------- ---------- ---------- ------------ ------------
                                      1        601          2  10.00000000  10.20000000
                                      1        602          2  10.20000000  10.40400000
                                      1        603          2  10.40400000  10.61208000
                                      1        604          1  10.61208000  10.71820080
                                      1        605          6  10.71820080  11.36129285
                                      1        606          3  11.36129285  11.70213163
                 PROJECTION_DETAILS_SID PERIOD_SID     GROWTH   MULTIPLIER   OUR_RESULT
--------------------------------------- ---------- ---------- ------------ ------------
                                      1        601          2   1.02000000  10.20000000
                                      1        602          2   1.04040000  10.40400000
                                      1        603          2   1.06120800  10.61208000
                                      1        604          1   1.07182008  10.71820080
                                      1        605          6   1.13612928  11.36129285
                                      1        606          3   1.17021316  11.70213163
我假设period\u sid递增1,因此我使用.period\u sid=b.period\u sid+1作为联接条件。如果在实际数据中不是这样,则需要使用行数分析函数略微修改查询

编辑
@科迪科,谢谢。有没有其他可能达到这个结果 而不是递归cte,因为递归cte具有类似的性能 当然是while循环

对。在Oracle中,您可以创建自己的聚合函数来执行数字链的乘法运算,其方式与内置求和函数的方式类似==>X1+X2+…+Xn,但实际上是X1*X2*…*Xn。 例如:

create or replace TYPE MyCumulativeMultiply_type
AS OBJECT (

cumulativeMultiplyResult NUMBER,

STATIC FUNCTION odciaggregateinitialize(ctx IN OUT MyCumulativeMultiply_type) RETURN NUMBER,

MEMBER FUNCTION odciaggregateiterate(self IN OUT MyCumulativeMultiply_type, your_parameter_to_aggregate IN NUMBER) RETURN NUMBER,

MEMBER FUNCTION odciaggregatemerge(self IN OUT MyCumulativeMultiply_type, ctx2 IN MyCumulativeMultiply_type) RETURN NUMBER,

MEMBER FUNCTION odciaggregateterminate(self IN MyCumulativeMultiply_type, returnvalue OUT NUMBER, flags IN NUMBER) RETURN NUMBER
);
/
CREATE OR REPLACE TYPE BODY MyCumulativeMultiply_type
IS
    STATIC FUNCTION odciaggregateinitialize(ctx IN OUT MyCumulativeMultiply_type)
        RETURN NUMBER
    IS
    BEGIN
          -- instantiate our type, NULL the dummy attribute
        ctx  := MyCumulativeMultiply_type( 1 );
        RETURN odciconst.success;
    END odciaggregateinitialize;

    MEMBER FUNCTION odciaggregateiterate(self IN OUT MyCumulativeMultiply_type, your_parameter_to_aggregate IN NUMBER)
        RETURN NUMBER
    IS
    BEGIN
        self.cumulativeMultiplyResult := self.cumulativeMultiplyResult * your_parameter_to_aggregate; 
        RETURN odciconst.success;
    END odciaggregateiterate;

    MEMBER FUNCTION odciaggregatemerge(self IN OUT MyCumulativeMultiply_type, ctx2 IN MyCumulativeMultiply_type)
        RETURN NUMBER
    IS
    BEGIN
       self.cumulativeMultiplyResult := self.cumulativeMultiplyResult * ctx2.cumulativeMultiplyResult;
        RETURN odciconst.success;
    END odciaggregatemerge;

    MEMBER FUNCTION odciaggregateterminate(self          IN   MyCumulativeMultiply_type,
                                           returnvalue      OUT NUMBER,
                                           flags         IN     NUMBER
                                          )
        RETURN NUMBER
    IS
    BEGIN
        returnvalue := self.cumulativeMultiplyResult;
        RETURN odciconst.success;
    END odciaggregateterminate;
END;
/

CREATE OR REPLACE FUNCTION cumulative_multiply(arg NUMBER)
    RETURN NUMBER
    PARALLEL_ENABLE
    AGGREGATE USING MyCumulativeMultiply_type;
    /
现在一个查询是:

select t1.*
      , cumulative_multiply(  1 + growth/100 ) OVER (order by period_sid ) as multiplier
      , 10 * cumulative_multiply(  1 + growth/100 ) OVER (order by period_sid ) as our_result
from t1;
结果是:

                 PROJECTION_DETAILS_SID PERIOD_SID     GROWTH         BASE   OUR_RESULT
--------------------------------------- ---------- ---------- ------------ ------------
                                      1        601          2  10.00000000  10.20000000
                                      1        602          2  10.20000000  10.40400000
                                      1        603          2  10.40400000  10.61208000
                                      1        604          1  10.61208000  10.71820080
                                      1        605          6  10.71820080  11.36129285
                                      1        606          3  11.36129285  11.70213163
                 PROJECTION_DETAILS_SID PERIOD_SID     GROWTH   MULTIPLIER   OUR_RESULT
--------------------------------------- ---------- ---------- ------------ ------------
                                      1        601          2   1.02000000  10.20000000
                                      1        602          2   1.04040000  10.40400000
                                      1        603          2   1.06120800  10.61208000
                                      1        604          1   1.07182008  10.71820080
                                      1        605          6   1.13612928  11.36129285
                                      1        606          3   1.17021316  11.70213163

不幸的是,我不知道上述方法在SQL Server中是可行的。

@reto感谢您的指导。我试过用计算机运行乘法运算。但任何使用超前、滞后或任何其他技术的方法都对我有好处。@reto谢谢你的指导。我试过用计算机运行乘法运算。但任何使用超前、滞后或其他技术的方法都对我有好处。@kordiko谢谢。由于递归cte与while循环具有类似的性能,因此除了递归cte之外,还有其他方法可以实现该结果吗?@kordiko,谢谢。由于递归cte的性能与while loop.Thank相似,因此除了递归cte之外,还有其他可能实现此结果的方法吗。由于递归cte的性能与while loop.Thank相似,因此除了递归cte之外,还有其他可能实现此结果的方法吗。由于递归cte具有类似while循环的性能,因此除了递归cte之外,还有其他可能实现该结果的方法吗。
WITH our_recursive_query(projection_details_sid,  period_sid, growth,  base,  our_result)
AS (
    select projection_details_sid,  period_sid, growth, 
           10.0 as base, 
           10 * ( 1 + growth/100) As our_result
    from t1 where period_sid = 601

    UNION ALL

    SELECT a.projection_details_sid,  a.period_sid, a.growth, 
           b.our_result as base, 
           b.our_result * ( 1 + a.growth/100) As our_result
    FROM t1 a
    JOIN our_recursive_query b
    ON a.period_sid = b.period_sid + 1
)
SELECT * FROM our_recursive_query