質問

私は4ユーロの費用がかかる製品があり、このお金を3つの部門に分割する必要があります。 2番目の列では、この製品の行数を取得し、部門数を分割する必要があります。

私の質問:

select
   department, totalvalue,
   (totalvalue / (select count(*) from departments d2 where d2.department = p.product))
       dividedvalue
from products p, departments d
where d.department = p.department

Department  Total Value  Divided Value
----------  -----------  -------------
A           4            1.3333333
B           4            1.3333333
C           4            1.3333333

しかし、値を合計すると、3,999999を取得します。もちろん、数百行で大きな違いがあります... 2つの10進数とラウンドの最後の値を定義する機会はありますか? (私の結果は1.33 1.33 1.34になります)つまり、最後の行を調整する方法はありますか?

役に立ちましたか?

解決

6つの精度の小数がある場合、最終番号を2つの小数に丸めると、1セントの差に気付くために約5,000のトランザクションが必要になります。デシマルの数を許容レベルに増やすと、ほとんどの問題が排除されます。つまり、1セントの違いに気付くために約5,000,000のトランザクションが必要になります。

他のヒント

これを処理するには、各行について次のことを行う必要があります。

  • 部門を実行します
  • 結果を適切な数セントに丸めます
  • 丸い量と部門操作の結果の違いを合計します
  • 差の合計が最低小数の場所(この場合は0.01)を超えると、次の分割操作の結果(丸め後)にその量を追加します。

これにより、分数量が行全体に分配されます。残念ながら、SQLで簡単なクエリでこれを行う簡単な方法はありません。おそらく、これを手続きコードで実行する方が良いでしょう。

それがどれほど重要かについては、金融アプリケーションや機関に関しては、このようなことは、たとえそれがペニーだけであっても、たとえそれがすべての数の記録しか起こらないとしても、非常に重要です。通常、ユーザーは、値(または通貨の単位が何であれ)に値が正確に結び付けられているのを見たいと考えています。

最も重要なことは、あなたは次のようなエクスプロイトを許可したくないということです 「スーパーマンIII」 また "オフィススペース" 発生することが。

たぶん、あなたは合計-sum(a、b、c)になるfourt列を作ることができます。しかし、それはあなたがしたいことに依存します、あなたが正確な価値を必要とするならば、あなたは画分を保持することができます、他のもの、切り捨て、仮想損失を気にしないでください

また、特定の値の丸めの違いを次の数値に追加するだけで(丸くする前に)実行することもできます。これにより、パイルは常に同じサイズのままです。

これは、によって提供されたアルゴリズムのTSQL(Microsoft SQL Server)の実装です マーティン:

-- Set parameters.
DECLARE @departments INTEGER = 3;
DECLARE @totalvalue DECIMAL(19, 7) = 4.0;

WITH
CTE1 AS
(
    -- Create the data upon which to perform the calculation.
    SELECT

        1 AS Department
        , @totalvalue AS [Total Value]
        , CAST(@totalvalue / @departments AS DECIMAL(19, 7)) AS [Divided Value]
        , CAST(ROUND(@totalvalue / @departments, 2) AS DECIMAL(19, 7)) AS [Rounded Value]

    UNION ALL

    SELECT

        CTE1.Department + 1
        , CTE1.[Total Value]
        , CTE1.[Divided Value]
        , CTE1.[Rounded Value]

    FROM

        CTE1

    WHERE

        Department < @departments
),

CTE2 AS
(
    -- Perform the calculation for each row.
    SELECT

        Department
        , [Total Value]
        , [Divided Value]
        , [Rounded Value]
        , CAST([Divided Value] - [Rounded Value] AS DECIMAL(19, 7)) AS [Rounding Difference]
        , [Rounded Value] AS [Calculated Value]

    FROM

        CTE1

    WHERE

        Department = 1

    UNION ALL

    SELECT

        CTE1.Department
        , CTE1.[Total Value]
        , CTE1.[Divided Value]
        , CTE1.[Rounded Value]
        , CAST(CTE1.[Divided Value] + CTE2.[Rounding Difference] - ROUND(CTE1.[Divided Value] + CTE2.[Rounding Difference], 2) AS DECIMAL(19, 7))
        , CAST(ROUND(CTE1.[Divided Value] + CTE2.[Rounding Difference], 2) AS DECIMAL(19, 7))

    FROM

        CTE2

            INNER JOIN CTE1
                ON CTE1.Department = CTE2.Department + 1

)

-- Display the results with totals.
SELECT 

    Department
    , [Total Value]
    , [Divided Value]
    , [Rounded Value]
    , [Rounding Difference]
    , [Calculated Value]

FROM 

    CTE2

UNION ALL

SELECT

    NULL
    , NULL
    , SUM([Divided Value])
    , SUM([Rounded Value])
    , NULL
    , SUM([Calculated Value])

FROM

    CTE2

;

出力:

enter image description here

上部に必要な数字をプラグインできます。このアルゴリズムに数学的な証明があるかどうかはわかりません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top