【问题标题】:Price calculation based on the unit entered基于输入单位的价格计算
【发布时间】:2016-08-05 16:47:47
【问题描述】:

表架构:

CREATE TABLE [dbo].[TblPriceDetails](
    [PriceID] [int] IDENTITY(1,1) NOT NULL,
    [VID] [int] NOT NULL,
    TypeID int not null,
    [RangeStart] [decimal](18, 3) NOT NULL,
    [RangeEnd] [decimal](18, 3) NOT NULL,
    [Price] [decimal](18, 2) NOT NULL,
    [ExtraLoad] [decimal](18, 3) NULL,
    [ExtraPrice] [decimal](18, 2) NULL
)
GO

样本数据

Insert into dbo.TblPriceDetails values (1,1, 0,0.250,10,0,0)
Insert into dbo.TblPriceDetails values (1,1, 0.251,0.500,15,0.500,15)
Insert into dbo.TblPriceDetails values (1,1, 3,5,40,1,25)
GO
Insert into dbo.TblPriceDetails values (1,2, 0,0.250,15,0,0)
Insert into dbo.TblPriceDetails values (1,2, 0.251,0.500,20,0.500,20)
Insert into dbo.TblPriceDetails values (1,2, 3,5,50,1,30)
GO

预期输出:

对于 VID = 1 和 TypeID = 1 以及给定值 0.300

  • 由于输入单元介于 RangeStart 0.251 和 RangeEnd 0.500 之间 结果价格为 15

对于 VID = 1 和 TypeID = 1 以及给定值 0.600

  • 根据 0.500 之前的数据,价格为 15,对于每个 extraLoad 高达 0.500 又是 15。所以最终价格将是 30

对于 VID = 1 和 TypeID = 1 和给定值 1.500

  • 根据 0.500 之前的数据,价格为 15。每增加 0.500 它的另一个 15,所以对于剩余的 1 个单位,它将是 15 * 2。 最终价格为 45

对于 VID = 1 和 TypeID = 1 和给定值 5.5

  • 根据 5.000 之前的数据,价格为 40。每多出 1 个单位,则再增加 25 个单位,因此最终价格为 65 个

在为此编写查询时需要帮助。与我的其他问题不同,我还没有一个查询来显示我到目前为止的想法。截至目前,我无法为此制定逻辑并提出通用查询。

【问题讨论】:

    标签: sql-server-2012 sql-server-2008-r2 sql-server-2014


    【解决方案1】:

    您似乎正在计算邮费。诀窍是加入下一个权重等级的RangeStartLEAD 将帮助您做到这一点:

    ;WITH
        AdjustedPriceDetails AS
        (
            SELECT      VID, TypeID, RangeStart, RangeEnd, Price, ExtraLoad, ExtraPrice
                    ,   ISNULL(LEAD(RangeStart, 1) OVER (PARTITION BY VID, TypeID ORDER BY RangeStart), 1000000) AS NextRangeStart
            FROM        TblPriceDetails
        )
    
    
    SELECT      T.*
            ,   A.Price + IIF(T.Value <= A.RangeEnd, 0, CEILING((T.Value - A.RangeEnd) / A.ExtraLoad) * A.ExtraPrice)
                                                AS FinalPrice
    FROM        #TestData               T
    INNER JOIN  AdjustedPriceDetails    A       ON A.RangeStart <= T.Value AND T.Value < A.NextRangeStart
    

    解释:

    • LEAD(RangeStart, 1) OVER (PARTITION BY VID, TypeID ORDER BY RangeStart) 获取具有相同 VIDTypeID 的下一行的 RangeStart
    • 您最终将达到最高权重等级。所以ISNULL(..., 1000000) 使这一层看起来以 1M 结束。 1M 只是无穷大的代名词。

    编辑:如果您想在 SQL Server 2008 上使用此功能,请更改 CTE:

    ;WITH
        tmp AS
        (
            SELECT      VID, TypeID, RangeStart, RangeEnd, Price, ExtraLoad, ExtraPrice
                    ,   ROW_NUMBER() OVER (PARTITION BY VID, TypeID ORDER BY RangeStart) AS RowNumber
            FROM        TblPriceDetails
        ),
        AdjustedPriceDetails AS
        (
            SELECT      T1.VID, T1.TypeID, T1.RangeStart, T1.RangeEnd, T1.Price, T1.ExtraLoad, T1.ExtraPrice
                    ,   ISNULL(T2.RangeStart, 1000000) AS NextRangeStart
            FROM        tmp     T1
            LEFT JOIN   tmp     T2  ON T1.VID = T2.VID AND T1.TypeId = T2.TypeID AND T1.RowNumber + 1 = T2.RowNumber
        )
    

    如果你想知道#TestData 是什么(你可能不需要它)

    CREATE TABLE #TestData
    (
            VID         int
    ,       TypeID      int
    ,       Value       float
    )
    
    INSERT INTO #TestData
                ( VID, TypeID, Value)
        VALUES  ( 1, 1, 0.3 )
            ,   ( 1, 1, 0.6 )
            ,   ( 1, 1, 1.5 )
            ,   ( 1, 1, 5.5 )
    

    【讨论】:

    • 感谢您的宝贵时间。我对你的答案投了赞成票。它在最新版本的 SQL 中运行良好。但我相信 LEAD 功能不会出现在 SQL Server 2008 R2 中。还有其他替代方法可以在 2008 R2 中使用吗?
    • 更新后的代码抛出这个错误 -- ')' 附近的语法不正确。
    • 您需要在指定 CTE 后添加SELECT。在2012代码中使用SELECT
    • 是的,它有效。最后澄清一下...如果我必须将它作为一个存储过程,它以 VID、TypeID 和单位值作为参数,并且它应该将价格作为输出返回,我应该改变什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-25
    • 1970-01-01
    • 2019-08-03
    • 2013-11-14
    • 2019-02-02
    • 2019-05-29
    • 1970-01-01
    相关资源
    最近更新 更多