3

次のようなデータテーブルがあります。

Group   ID    M0    M1    ...    M20
------------------------------------
    1    1    10    -2    ...     54
    1    2    -8    10    ...    -20
    2    6   -10    12    ...      0
    2    4    45    52    ...      0
    2    5    12   102    ...      0

次のように、グループごとにデータをグループ化しています。

SELECT Group
     , round(sum(M0+M1+M2+...+M20)/count(ID),2) as profit
     , round(sum(M0),2) as M0
     , round(sum(M1),2) as M1
     , ...
     , round(sum(M20),2) as M20
FROM
    data_table
GROUP BY
    Group

追加する必要があるのは、M0 から M20 の列に基づく IRR です。

次のような IRR 関数を見つけました。

CREATE FUNCTION [dbo].[ufn_IRR]
  (
   @strIDs VARCHAR(8000),
   @guess DECIMAL(30,10)
  )
RETURNS DECIMAL(30, 10)
AS 
  BEGIN
    DECLARE @t_IDs TABLE (
        id INT IDENTITY(0, 1),
        value DECIMAL(30, 10)
    )
    DECLARE @strID VARCHAR(12),@sepPos INT,@NPV DECIMAL(30, 10)
    SET @strIDs = COALESCE(@strIDs + ',', '')
    SET @sepPos = CHARINDEX(',', @strIDs)
    WHILE @sepPos > 0 
      BEGIN
        SET @strID = LEFT(@strIDs, @sepPos - 1)
        INSERT INTO @t_IDs ( value ) SELECT ( CAST(@strID AS DECIMAL(20, 10)) ) WHERE ISNUMERIC(@strID) = 1
        SET @strIDs = RIGHT(@strIDs, DATALENGTH(@strIDs) - @sepPos)
        SET @sepPos = CHARINDEX(',', @strIDs)
      END

    SET @guess = CASE WHEN ISNULL(@guess, 0) <= 0 THEN 0.00001 ELSE @guess END

    SELECT @NPV = SUM(value / POWER(1 + @guess, id)) FROM @t_IDs
    WHILE @NPV > 0 
      BEGIN
        SET @guess = @guess + 0.00001
        SELECT @NPV = SUM(value / POWER(1 + @guess, id)) FROM @t_IDs
      END
    RETURN @guess
  END

使用例は次のようになります。

SELECT  dbo.ufn_IRR('-4000,1200,1410,1875,1050',0.00001)

しかし、私の場合、次のように、列から文字列を作成することを避けたいと思います:

 SELECT  dbo.ufn_IRR(
    cast(round(sum([M0]), 2) AS NVARCHAR)+','
   +cast(round(sum([M1]), 2) AS NVARCHAR)+','
   +cast(round(sum([M2]), 2) AS NVARCHAR)+','
   +cast(round(sum([M3]), 2) AS NVARCHAR)+','
   +cast(round(sum([M4]), 2) AS NVARCHAR)+','
   +...+','
   +cast(round(sum([M20]), 2) AS NVARCHAR)
 ,0.00001)

最初に文字列を作成してから、関数内でそれをテーブルにカットするのは無意味だと思います。
列を渡すことができるように IRR 関数を変更したいのですが、それを行う方法がわかりません:/

4

4 に答える 4

1
CREATE FUNCTION [dbo].[ufn_IRR]
  (
   @s0 DECIMAL(30,10),
   @s1 DECIMAL(30,10),
   @s2 DECIMAL(30,10),
   @s3 DECIMAL(30,10),
   @s4 DECIMAL(30,10),
   @s5 DECIMAL(30,10),
   @s6 DECIMAL(30,10),
   @s7 DECIMAL(30,10),
   @s8 DECIMAL(30,10),
   @s9 DECIMAL(30,10),
   @s10 DECIMAL(30,10),
   @s11 DECIMAL(30,10),
   @s12 DECIMAL(30,10),
   @s13 DECIMAL(30,10),
   @s14 DECIMAL(30,10),
   @s15 DECIMAL(30,10),
   @s16 DECIMAL(30,10),
   @s17 DECIMAL(30,10),
   @s18 DECIMAL(30,10),
   @s19 DECIMAL(30,10),
   @s20 DECIMAL(30,10),
   @guess DECIMAL(30,10)
  )
RETURNS DECIMAL(30, 10)
AS 
  BEGIN
    DECLARE @t_IDs TABLE (
        id INT IDENTITY(0, 1),
        value DECIMAL(30, 10)
    )
    Declare @NPV DECIMAL(30, 10)

    INSERT INTO @t_IDs (value) values (@s0);
    INSERT INTO @t_IDs (value) values (@s1);
    INSERT INTO @t_IDs (value) values (@s2);
    INSERT INTO @t_IDs (value) values (@s3);
    INSERT INTO @t_IDs (value) values (@s4);
    INSERT INTO @t_IDs (value) values (@s5);
    INSERT INTO @t_IDs (value) values (@s6);
    INSERT INTO @t_IDs (value) values (@s7);
    INSERT INTO @t_IDs (value) values (@s8);
    INSERT INTO @t_IDs (value) values (@s9);
    INSERT INTO @t_IDs (value) values (@s10);
    INSERT INTO @t_IDs (value) values (@s11);
    INSERT INTO @t_IDs (value) values (@s12);
    INSERT INTO @t_IDs (value) values (@s13);
    INSERT INTO @t_IDs (value) values (@s14);
    INSERT INTO @t_IDs (value) values (@s15);
    INSERT INTO @t_IDs (value) values (@s16);
    INSERT INTO @t_IDs (value) values (@s17);
    INSERT INTO @t_IDs (value) values (@s18);
    INSERT INTO @t_IDs (value) values (@s19);
    INSERT INTO @t_IDs (value) values (@s20);

    SET @guess = CASE WHEN ISNULL(@guess, 0) <= 0 THEN 0.00001 ELSE @guess END

    SELECT @NPV = SUM(value / POWER(1 + @guess, id)) FROM @t_IDs
    WHILE @NPV > 0 
      BEGIN
        SET @guess = @guess + 0.00001
        SELECT @NPV = SUM(value / POWER(1 + @guess, id)) FROM @t_IDs
      END
    RETURN @guess
  END

そしてそれを使う

dbo.ufn_IRR(round(sum([M0]), 2),
            round(sum([M1]), 2),
            .....
            round(sum([M20]),2),
            0.00001)
于 2012-08-22T14:16:29.850 に答える
1

私の提案するアプローチは...

独立した を定義しtable @t_IDs ( term INT, value DECIMAL )ます。を呼び出す前にufn_IRR()、 を手動で入力tablerows (1, M0), (2, M1) ... (n, M20)ます。(私のSQL知る限り、これはループ ステップのように思えますが、おそらくSQL-Server1 つのステートメントで実行できますか?) 次に、単にパラメーターを指定ufn_IRR()して呼び出し@guessます。最初に、に分割されたufn_IRR()最初のビットを変更して破棄する必要があります。@strIDs@t_IDs table

このアプローチには、さまざまなサイズのデータ​​を処理できるという利点があります。

ufn_IRR()線形根探索法を使用します。大規模または反復的なタスクの場合は、おそらく他の方法を検討してください。「内部収益率」に関するウィキペディアのページには、いくつかの提案があります。

于 2012-08-22T15:00:07.627 に答える
1

それを行うための1つの方法をスケッチします。

まず、この 1 つのテーブルを操作する手順を次の手順で記述します。

  • 一時テーブルを作成する
  • クエリを使用してベース テーブルから入力しselect... unpivot...ます (21 列を 1 列 21 行のデータセットに変換します)。
  • 一時テーブルに対して計算を実行します

欠点は、1 つのテーブルしか処理できず、アンピボット クエリで 21 列の名前をハードコーディングする必要があることです。これはあまり柔軟ではありません。

より洗練された手順は、#temp テーブルを作成し、動的 ​​SQL を使用して、処理が必要であるとプログラムで判断した (任意のテーブルの) 任意の列に基づいてアンピボットを構築することです。

それを関数に変換するには、テーブル変数を作成し、それをパラメーターとして使用する必要があります。次に、関数を呼び出す必要があるルーチンは、#temp テーブルを作成してデータを入力し、それを関数に渡す必要があります。

私が言ったように、それはかなり複雑になります。物事をすばやく終わらせるために、@valexhome の回答を使用し、必要に応じて後で更新/アップグレードすることを心配します。

于 2012-08-22T18:40:48.130 に答える