在SQL Server中按范围分组

拉瑟·埃德斯维克(Lasse Edsvik)

我有范围的分组问题。我正在尝试将结果按瑞典克朗(SEK)的每十分之一进行分组。问题是当PriceSEK与LowerBoundSEK和UpperBoundSEK匹配时。

正如您在下面看到的,我添加了-0.001,此刻仅作为所需结果的可视化表示。仍按0.1分组。

如何调整此分组以获得在正确范围内两次计数的0.4的期望结果?(0.301-0.4)

http://sqlfiddle.com/#!6/f7624/3

测试SQL

CREATE TABLE #Test (
    ID int NOT NULL IDENTITY(1,1),
    PriceEUROCent smallmoney NOT NULL,
    DateSent datetime NOT NULL,
    Quantity int NOT NULL,
    SomeID int NOT NULL,
    CurrencyID int NOT NULL
)

CREATE TABLE #Currencies (
    CurrencyID int IDENTITY(1, 1),
    CurrencyValue numeric(17,3)
)

INSERT INTO #Currencies SELECT 10 --9.617


INSERT INTO #Test
    (PriceEUROCent, DateSent, Quantity, SomeID, CurrencyID)
    VALUES
        ('2.70', '2016-09-27 11:00', 1, 1, 1),
        ('3.00', '2016-09-27 12:00', 1, 1, 1),
        ('4.0', '2016-09-27 14:00', 1, 1, 1),
        ('4.0', '2016-09-27 14:00', 1, 1, 1),
        ('6.80', '2016-09-27 12:00', 1, 1, 1),
        ('8.00', '2016-09-28 14:01', 3, 1, 1)



DECLARE @RangeWidth numeric(17,3), @Currency numeric(17,3), @RangeWidthSEK numeric(17, 3)

SET @RangeWidth = .1

SELECT 
    DT.SomeID,
    DT.LowerBoundSEK,
    DT.UpperBoundSEK,
    DT.SomeDate,
    SUM(DT.Quantity) AS Quantity,
    SUM(DT.SumPriceSEK) AS SumPriceSEK
    FROM (
        SELECT 
            (PriceEUROCent / 100) * C.CurrencyValue AS PriceSEK,
            FLOOR((PriceEUROCent / 10) * C.CurrencyValue) * @RangeWidth + 0.001 AS LowerBoundSEK,
            (FLOOR((PriceEUROCent / 10) * C.CurrencyValue) * @RangeWidth) + @RangeWidth AS UpperBoundSEK,
            (FLOOR((PriceEUROCent / 10) * C.CurrencyValue) * @RangeWidth) + @RangeWidth AS SumPriceSEK,
            SomeID,
            Quantity,
            CONVERT(VARCHAR(10), DateSent, 120) AS SomeDate
            FROM #Test T
                JOIN #Currencies C ON T.CurrencyID = C.CurrencyID
    ) DT
    GROUP BY
    FLOOR(DT.PriceSEK/@RangeWidth), 
    DT.SomeDate,
    DT.LowerBoundSEK,
    DT.UpperBoundSEK,
    DT.SomeID




-- DEBUG SELECT
SELECT T.DateSent, T.Quantity, T.SomeID, C.CurrencyValue,
    (PriceEUROCent / 100) * C.CurrencyValue * T.Quantity AS PriceSEK,
    PriceEUROCent * T.Quantity AS PriceEUROCent
    FROM #Test T
    JOIN #Currencies C ON T.CurrencyID = C.CurrencyID

编辑:

所需结果:

1   0.201   0.3 2016-09-27  2   0.300
1   0.301   0.4 2016-09-27  2   0.800
1   0.601   0.7 2016-09-27  1   0.700
1   0.701   0.8 2016-09-28  3   2.400
拉瑟·埃德斯维克(Lasse Edsvik)

我通过更多测试解决了它。最大的变化是CEILING,改变的JOIN一个范围加入。

CREATE TABLE #Test (
    ID int NOT NULL IDENTITY(1,1),
    PriceEUROCent smallmoney NOT NULL,
    DateSent datetime NOT NULL,
    Quantity int NOT NULL,
    SomeID int NOT NULL,
    CurrencyID int NOT NULL
)

CREATE TABLE #Currencies (
    CurrencyID int IDENTITY(1, 1),
    CurrencyValue numeric(17,3)
)

INSERT INTO #Currencies SELECT 10 --9.617


INSERT INTO #Test
    (PriceEUROCent, DateSent, Quantity, SomeID, CurrencyID)
    VALUES
        ('1', '2016-09-27 11:00', 1, 1, 1),
        ('2', '2016-09-27 11:00', 1, 1, 1),
        ('2.200', '2016-09-27 12:00', 1, 1, 1),
        ('2.999', '2016-09-27 12:00', 1, 1, 1),
        ('3', '2016-09-27 12:00', 1, 1, 1),
        ('4.0', '2016-09-27 14:00', 1, 1, 1), 
        ('4.0', '2016-09-27 14:00', 1, 1, 1),
        ('6.80', '2016-09-27 12:00', 1, 1, 1),
        ('7.1', '2016-09-27 14:01', 3, 1, 1)


DECLARE @RangeWidth numeric(17,3)

SET @RangeWidth = .1

SELECT 
    R.SomeID,
    R.DateSent,
    R.LowerBoundSEK,
    R.UpperBoundSEK,
    SUM(R.UpperBoundSEK * T.Quantity) AS SumPrice,
    SUM(T.Quantity) AS Quantity
    FROM
    (
        SELECT
            T.SomeID,
            C.CurrencyValue,
            CONVERT(VARCHAR(10), T.DateSent, 120) AS DateSent,
            (CEILING((PriceEUROCent / 10) * C.CurrencyValue)
                * @RangeWidth) + 0.001 - @RangeWidth
                    AS LowerBoundSEK,
            (CEILING((PriceEUROCent / 10) * C.CurrencyValue) * @RangeWidth) 
                AS UpperBoundSEK
            FROM #Test T
                JOIN #Currencies C ON T.CurrencyID = C.CurrencyID
                    GROUP BY 
                        CEILING((PriceEUROCent / 10) * C.CurrencyValue),
                        C.CurrencyValue,
                        T.SomeID,
                        CONVERT(VARCHAR(10), T.DateSent, 120)
    ) R
        JOIN #Test T ON (T.PriceEUROCent * R.CurrencyValue / 100) 
                            BETWEEN R.LowerBoundSEK AND R.UpperBoundSEK 
        GROUP BY
            R.SomeID,
            R.DateSent,
            R.LowerBoundSEK,
            R.UpperBoundSEK
                ORDER BY 
                    R.SomeID,
                    R.DateSent,
                    R.LowerBoundSEK

DROP TABLE #Test
DROP TABLE #Currencies

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章