在SQL Server中按范围分组

时间:2016-10-06 08:33:28

标签: sql sql-server

我有范围的分组问题。我试图将结果分组为每10瑞典克朗(瑞典克朗)。问题是当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

1 个答案:

答案 0 :(得分:0)

我使用更多测试解决了它。最大变化为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