GROUP BY INTERVALS

时间:2017-12-07 13:52:10

标签: sql sql-server group-by average

我想取多行表的平均值并将它们插入视图中:

我的表:

  • 日期(日期时间)
  • 期间(int) - 半小时
  • 价格(十进制(18,2)

示例数据:

Date     | Period | Price 
---------+--------+---------
07-12-17 |  47    | 10 
07-12-17 |  48    | 20
07-12-17 |   1    | 30
07-12-17 |   2    | 40
07-12-17 |   3    | 50
07-12-17 |   4    | 60
07-12-17 |   5    | 70
07-12-17 |   6    | 80 
07-12-17 |   7    | 10
07-12-17 |   8    | 10
07-12-17 |   9    | 10
07-12-17 |  10    | 10
07-12-17 |  11    | 20
07-12-17 |  12    | 20
07-12-17 |  13    | 20
07-12-17 |  14    | 20

我的期间是半小时从1-48开始,我想取8个期间的平均价格,并将该价格分配给该集合中的所有8个期间。由于时差,我从半小时47开始而不是1:

间隔:

[48-6], [7-14], [15-22], [23-30], [31-38], [39-46]

我希望生成的视图看起来像:

Date     | Period | Price 
---------+--------+---------
07-12-17 |   47   | 45 
07-12-17 |   48   | 45
07-12-17 |    1   | 45
07-12-17 |    2   | 45
07-12-17 |    3   | 45
07-12-17 |    4   | 45
07-12-17 |    5   | 45
07-12-17 |    6   | 45
07-12-17 |    7   | 15
07-12-17 |    8   | 15
07-12-17 |    9   | 15
07-12-17 |   10   | 15
07-12-17 |   11   | 15
07-12-17 |   12   | 15
07-12-17 |   13   | 15
07-12-17 |   14   | 15

我无法提出完整的查询,但我认为它必须是GROUP BY并且可能带有HAVING Statement。

希望你能帮忙!

2 个答案:

答案 0 :(得分:1)

使用窗口功能可以非常轻松有效地完成。

示例数据

DECLARE @T TABLE (dt datetime2(0), Period int, Price money);
INSERT INTO @T VALUES
('2017-12-06', 39, 90),
('2017-12-06', 40, 90),
('2017-12-06', 41, 90),
('2017-12-06', 42, 90),
('2017-12-06', 43, 90),
('2017-12-06', 44, 90),
('2017-12-06', 45, 90),
('2017-12-06', 46, 90),

('2017-12-06', 47, 10),
('2017-12-06', 48, 20),
('2017-12-07',  1, 30),
('2017-12-07',  2, 40),
('2017-12-07',  3, 50),
('2017-12-07',  4, 60),
('2017-12-07',  5, 70),
('2017-12-07',  6, 80),

('2017-12-07',  7, 10),
('2017-12-07',  8, 10),
('2017-12-07',  9, 10),
('2017-12-07', 10, 10),
('2017-12-07', 11, 20),
('2017-12-07', 12, 20),
('2017-12-07', 13, 20),
('2017-12-07', 14, 20),

('2017-12-07', 15, 40),
('2017-12-07', 16, 40),
('2017-12-07', 17, 40),
('2017-12-07', 18, 40),
('2017-12-07', 19, 30),
('2017-12-07', 20, 30),
('2017-12-07', 21, 30),
('2017-12-07', 22, 30);

<强>查询

SELECT
    dt
    ,Period
    ,Price
    ,DATEADD(minute, (Period-1)*30 + 60, dt) as d2
    ,DATEDIFF(hour, '2001-01-01', DATEADD(minute, (Period-1)*30 + 60, dt)) / 4 as d3
    ,AVG(Price) OVER (PARTITION BY 
        DATEDIFF(hour, '2001-01-01', DATEADD(minute, (Period-1)*30 + 60, dt)) / 4) AS AvgPrice
FROM @T AS MyTable
ORDER BY dt, Period;

我在输出中包含了中间结果d2d3,以帮助理解PARTITION BY中的公式。

<强>结果

+---------------------+--------+-------+---------------------+-------+----------+
|         dt          | Period | Price |         d2          |  d3   | AvgPrice |
+---------------------+--------+-------+---------------------+-------+----------+
| 2017-12-06 00:00:00 |     39 | 90.00 | 2017-12-06 20:00:00 | 37103 | 90.00    |
| 2017-12-06 00:00:00 |     40 | 90.00 | 2017-12-06 20:30:00 | 37103 | 90.00    |
| 2017-12-06 00:00:00 |     41 | 90.00 | 2017-12-06 21:00:00 | 37103 | 90.00    |
| 2017-12-06 00:00:00 |     42 | 90.00 | 2017-12-06 21:30:00 | 37103 | 90.00    |
| 2017-12-06 00:00:00 |     43 | 90.00 | 2017-12-06 22:00:00 | 37103 | 90.00    |
| 2017-12-06 00:00:00 |     44 | 90.00 | 2017-12-06 22:30:00 | 37103 | 90.00    |
| 2017-12-06 00:00:00 |     45 | 90.00 | 2017-12-06 23:00:00 | 37103 | 90.00    |
| 2017-12-06 00:00:00 |     46 | 90.00 | 2017-12-06 23:30:00 | 37103 | 90.00    |
| 2017-12-06 00:00:00 |     47 | 10.00 | 2017-12-07 00:00:00 | 37104 | 45.00    |
| 2017-12-06 00:00:00 |     48 | 20.00 | 2017-12-07 00:30:00 | 37104 | 45.00    |
| 2017-12-07 00:00:00 |      1 | 30.00 | 2017-12-07 01:00:00 | 37104 | 45.00    |
| 2017-12-07 00:00:00 |      2 | 40.00 | 2017-12-07 01:30:00 | 37104 | 45.00    |
| 2017-12-07 00:00:00 |      3 | 50.00 | 2017-12-07 02:00:00 | 37104 | 45.00    |
| 2017-12-07 00:00:00 |      4 | 60.00 | 2017-12-07 02:30:00 | 37104 | 45.00    |
| 2017-12-07 00:00:00 |      5 | 70.00 | 2017-12-07 03:00:00 | 37104 | 45.00    |
| 2017-12-07 00:00:00 |      6 | 80.00 | 2017-12-07 03:30:00 | 37104 | 45.00    |
| 2017-12-07 00:00:00 |      7 | 10.00 | 2017-12-07 04:00:00 | 37105 | 15.00    |
| 2017-12-07 00:00:00 |      8 | 10.00 | 2017-12-07 04:30:00 | 37105 | 15.00    |
| 2017-12-07 00:00:00 |      9 | 10.00 | 2017-12-07 05:00:00 | 37105 | 15.00    |
| 2017-12-07 00:00:00 |     10 | 10.00 | 2017-12-07 05:30:00 | 37105 | 15.00    |
| 2017-12-07 00:00:00 |     11 | 20.00 | 2017-12-07 06:00:00 | 37105 | 15.00    |
| 2017-12-07 00:00:00 |     12 | 20.00 | 2017-12-07 06:30:00 | 37105 | 15.00    |
| 2017-12-07 00:00:00 |     13 | 20.00 | 2017-12-07 07:00:00 | 37105 | 15.00    |
| 2017-12-07 00:00:00 |     14 | 20.00 | 2017-12-07 07:30:00 | 37105 | 15.00    |
| 2017-12-07 00:00:00 |     15 | 40.00 | 2017-12-07 08:00:00 | 37106 | 35.00    |
| 2017-12-07 00:00:00 |     16 | 40.00 | 2017-12-07 08:30:00 | 37106 | 35.00    |
| 2017-12-07 00:00:00 |     17 | 40.00 | 2017-12-07 09:00:00 | 37106 | 35.00    |
| 2017-12-07 00:00:00 |     18 | 40.00 | 2017-12-07 09:30:00 | 37106 | 35.00    |
| 2017-12-07 00:00:00 |     19 | 30.00 | 2017-12-07 10:00:00 | 37106 | 35.00    |
| 2017-12-07 00:00:00 |     20 | 30.00 | 2017-12-07 10:30:00 | 37106 | 35.00    |
| 2017-12-07 00:00:00 |     21 | 30.00 | 2017-12-07 11:00:00 | 37106 | 35.00    |
| 2017-12-07 00:00:00 |     22 | 30.00 | 2017-12-07 11:30:00 | 37106 | 35.00    |
+---------------------+--------+-------+---------------------+-------+----------+

答案 1 :(得分:0)

下面的代码示例应该让您接近您需要的位置。我不确定你的问题是如何计划建立你的小组的。如果您使用视图,您肯定希望使用交叉申请。这可以通过存储过程更简单地完成。有关“交叉申请”的详细信息,请参阅L部分,此处为https://docs.microsoft.com/en-us/sql/t-sql/queries/from-transact-sql

CREATE VIEW MyTableAveragePrices
AS
SELECT mt.Date, mt.Period, mtAverageGroup.AveragePrice, 
    CASE
       WHEN mtAvg.Period IN () THEN 'Period Group 1'
       WHEN mtAvg.Period IN () THEN 'Period Group 2'
    END AS PeriodGroup
FROM MyTable mt
    CROSS APPLY 
    (
    SELECT 
        AVERAGE(mtAvg.Price) AveragePrice,
        CASE
           WHEN mtAvg.Period IN () THEN 'Period Group 1'
           WHEN mtAvg.Period IN () THEN 'Period Group 2'
        END AS PeriodGroup
    FROM MyTable mtAvg
    WHERE
        mt.PeriodGroup = PeriodGroup
    GROUP BY
        CASE
           WHEN mtAvg.Period IN () THEN 'Period Group 1'
           WHEN mtAvg.Period IN () THEN 'Period Group 2'
        END
    ) mtAverageGroup
GO