需要帮助才能执行以下计算

时间:2016-07-06 05:47:26

标签: sql sql-server oracle

我有一定的价值,说10作为我计算的基础。现在对应于值10的第一个时期的增长是5。我想要的结果是10 *(1 + 5/100),其基本上是Base *(1 +%的生长)。第一期的结果价值将是下一期的新基数。假设下一个增长为6,则下一个周期的结果为(10(1 + 5/100))*(1 + 6/100)。这基本上是运行乘法,可以通过多种方式实现。现在有人请建议实现此计算的最佳方法。

  1. 10,5> 10(1 + 5/100)= 10.50
  2. 10.50,6 - > 10.50(1 + 6/100)= 11.1300
  3. 11.13,任何值等等
  4. 我尝试使用其他数据样本但基本上运行乘法的方法。

    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 
    

2 个答案:

答案 0 :(得分:2)

尝试递归查询 下面的示例适用于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

我假设period_sid增加1,因此我使用.period_sid = b.period_sid + 1作为连接条件。如果您的实际数据不是这样,则需要使用row_number分析函数轻微修改查询。

修改

  

@kordiko谢谢。有没有其他可能实现的结果   除了递归cte,因为递归cte具有类似的性能   while循环。

是。在Oracle中,您可以创建自己的聚合函数,该函数执行数字链的乘法 - 与内置sum函数的方式类似==> 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   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中可以采用上述方法。

答案 1 :(得分: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)