【问题标题】:Coalesce returning wrong value after a function call followed by multiplication在函数调用后合并返回错误值,然后是乘法
【发布时间】:2018-10-03 20:02:09
【问题描述】:

我有一份提供信息的报告,但我得到的信息不一致,这是因为 SQL 视图或嵌套在视图中的 SQL 函数似乎存在问题。我已经尝试找到一种调试 SQL 视图的方法,但是,看起来 SSMS 只能调试存储过程,所以我不太确定如何单步执行并查看发生了什么。这真的让我很难过,我不禁想知道这不是一个四舍五入的问题。 GetItemAverageCost RETURNS DECIMAL(12,2) 和 satli.QuantityIssuedAtStockUOM 中的 DataType 是 System.Int64 / bigint (旁注:我对为什么 LINQPad 显示该列的 2 种数据类型感到困惑。在左侧的树中,展开 satli 表并将鼠标悬停在QuantityIssuedAtStockUOM 会弹出气球 BigInt NOT NULL,但是当我 Take(100) 并将鼠标悬停在结果集中的列上时,它显示 System.Int64)。 Anyroad,这里是 COALESCE 函数。

COALESCE((dbo.GetItemAverageCost(ItemModel.IDItemModel)*sitli.QuantityIssuedAtStockUOM) / ISNULL(NULLIF(ItemModel.UOMFactor, 0),1),0) -- 259.73 --ROUND(COALESCE((dbo.GetItemAverageCost(ItemModel.IDItemModel)*sitli.QuantityIssuedAtStockUOM) / ISNULL(NULLIF(ItemModel.UOMFactor, 0),1),0),2) -- 259.73 --COALESCE(ROUND((dbo.GetItemAverageCost(ItemModel.IDItemModel)*sitli.QuantityIssuedAtStockUOM) / ISNULL(NULLIF(ItemModel.UOMFactor,2), 0),1),0) -- 259.70 --COALESCE((ROUND(dbo.GetItemAverageCost(ItemModel.IDItemModel),2)*sitli.QuantityIssuedAtStockUOM) / ISNULL(NULLIF(ItemModel.UOMFactor, 0),1),0) -- 259.73

原始/错误合并:

COALESCE(dbo.GetItemAverageCost(ItemModel.IDItemModel)*sitli.QuantityIssuedAtStockUOM,0)

我不确定还包括什么,但我没有找到很多在线资源可以深入了解这种情况。非常感谢您抽出宝贵时间。

编辑:GetItemAverageCost:

    ALTER FUNCTION GetItemAverageCost
        (
            @IDItemModel varchar(8000)
        )

        RETURNS DECIMAL(16,4)
        --RETURNS DECIMAL(12,2)
        AS
        BEGIN
        RETURN
        (
        SELECT 
            COALESCE(AVG(poli.UnitPrice),0) as AvgCost
--          COALESCE(ROUND(AVG(poli.UnitPrice),0),2) as AvgCost 260.00
        FROM ItemModel im
        LEFT JOIN VendorItem vi
            ON im.IDItemModel = vi.IDItemModel
        JOIN POLineItem poli
            ON vi.IDVendorItem = poli.IDVendorItem

        WHERE
            im.IDItemModel = @IDItemModel

        GROUP BY
            im.IDItemModel,
            im.ItemNumber
        )
        END

【问题讨论】:

  • 你能提供一些错误的例子吗?
  • @NetMage 感谢您的回复。运行给定报告时,不会引发任何错误。但是计算是关闭的。例如,零件编号 12 显示以 259.73 美元的成本发行了 24 件。但是,每个零件的成本为 10.82 美元,因此计算结果应为 259.68 美元。我不确定 5 美分的差价是从哪里来的。 259.73 美元是上述 COALESCE 函数的结果。希望这是有道理的。
  • 此外,还有其他部分在计算中显示没有错误。仅发布了 1 的部分似乎根本没有任何错误。问题似乎通常发生在发行多于一份时。但是,某些已发行超过 1 个的零件(例如 2、4、12 等)的成本计算正确。
  • 10.82 美元从何而来? GetItemAverageCost 第 12 部分返回什么?
  • @NetMage $10.82 是 GetItemAverageCost 的结果。 GetItemAverageCost 理论上返回 10.82 美元。

标签: sql linqpad coalesce


【解决方案1】:

修复;让您的函数返回 16,4 而不是 12,2,然后在乘以数量后舍入两位小数。

“运行给定报告时,不会抛出任何错误。但计算结果不正确。例如,零件号 12 显示以 259.73 美元的成本发出了 24 个零件。但是,每个零件的成本为 10.82 美元,因此计算结果应该是 259.68 美元。我不确定 5 美分的差值是从哪里来的。259.73 美元是上面 COALESCE 函数的结果。希望这是有道理的”

仅对第 12 部分独立于函数运行 SQL,您会看到平均值为 10.822083333333333333333333333333(10.82 5/24ths)

  • 24*单价 = $259.73
  • 单价 = 259.73/24
  • 单价 = 10.82 美元 5/24。

您会看到差异为 $.05

  • 10.82 5/24。 *24 = 259.73
  • 10.82 * 24 = 259.68

5cents 的差异不会均匀地进入剩余的 24。因此在使用您的函数时会出现舍入误差。

当您想到去商店买东西时,总是一分钱一分货。当您去加油站时,他们会收取最接近的 0.00001 美分。 (或在您的情况下为 4 位小数)

只有在乘以数量或实际现金需要易手时,才会进行四舍五入。如果过早完成,您会看到舍入错误。

因此,您可以消除过度/不足的四舍五入误差,并且您最多会收取比您应该收取的费用少或多的几分之一。

【讨论】:

  • 我听取了您的建议并将返回值更改为 DECIMAL(16,4),并且一直在使用 ROUND 函数,但似乎仍然得到了错误的返回值。我会继续这样做,直到我做对为止。
  • 所以我一直在尝试将 ROUND 函数放置在视图中的多个位置,但是,它们仍然无法生成正确的数字。我还意识到我在视图中使用了错误的 COALESCE 函数。我已经编辑了原始帖子以显示实际产生数量的 COALESCE。很抱歉造成混乱。
【解决方案2】:

好的,非常感谢一路上提供帮助的所有人。有几个问题阻止我得到正确的答案。一方面,我大部分时间都在使用不正确的表达方式。其次,在我弄清楚要使用哪个表达式之后,就是将 ROUND 函数放在正确的位置。

所以,我应该用来计算平均成本的表达式是:

COALESCE(dbo.GetItemAverageCost(Item.IDItemModel) / ISNULL(NULLIF(UOMFactor, 0),1),0)

当我将它移到 WorkOrderItemInstructionPartCosts 视图中时,我的报告产生了 10.82 美元。然后我将*sitli.QuantityIssuedAtStockUOM 添加到该行并获得 259.73 美元。然后我将 ROUND 函数应用于 COALESCE 函数,瞧!正在生成正确的值 ($259.68)。

最后一行如下所示:

ROUND(COALESCE(dbo.GetItemAverageCost(ItemModel.IDItemModel) / ISNULL(NULLIF(UOMFactor, 0),1),0),2)*sitli.QuantityIssuedAtStockUOM

再次感谢所有帮助我解决此问题的人,并很抱歉一开始就没有准确的信息。 最好的, 乔纳森

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-30
    • 2016-04-13
    • 1970-01-01
    • 2021-01-07
    • 2022-10-15
    • 2019-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多