-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path17_Time_Series.sql
More file actions
171 lines (153 loc) · 4.94 KB
/
17_Time_Series.sql
File metadata and controls
171 lines (153 loc) · 4.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/**************************************************************
* MySQL 8.0 Time Series Tutorial
* Description: This script demonstrates common time-series
* techniques in MySQL, including:
* - Creating a readings table
* - Filtering by time window
* - Running totals, moving averages, and differences
* - Bucketing values into fixed intervals
* - Manual history tracking as a MySQL alternative
* to SQL Server temporal tables
**************************************************************/
-------------------------------------------------
-- Region: 0. Initialization
-------------------------------------------------
USE mysql_course;
DROP TABLE IF EXISTS time_series_history;
DROP TABLE IF EXISTS time_series_data;
CREATE TABLE time_series_data
(
reading_id INT PRIMARY KEY AUTO_INCREMENT,
reading_time DATETIME NOT NULL,
sensor_id INT NOT NULL,
reading_value DECIMAL(10, 2) NOT NULL
) ENGINE = InnoDB;
CREATE TABLE time_series_history
(
history_id BIGINT PRIMARY KEY AUTO_INCREMENT,
reading_id INT NOT NULL,
old_value DECIMAL(10, 2) NOT NULL,
new_value DECIMAL(10, 2) NOT NULL,
changed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE = InnoDB;
DROP TRIGGER IF EXISTS trg_before_update_time_series_data;
DELIMITER //
/*
Track value changes manually because MySQL does not provide
system-versioned temporal tables.
*/
CREATE TRIGGER trg_before_update_time_series_data
BEFORE UPDATE ON time_series_data
FOR EACH ROW
BEGIN
IF OLD.reading_value <> NEW.reading_value THEN
INSERT INTO time_series_history (reading_id, old_value, new_value)
VALUES (OLD.reading_id, OLD.reading_value, NEW.reading_value);
END IF;
END //
DELIMITER ;
INSERT INTO time_series_data (reading_time, sensor_id, reading_value)
VALUES
('2023-01-01 08:00:00', 1, 10.50),
('2023-01-01 08:05:00', 1, 11.00),
('2023-01-01 08:10:00', 1, 10.75),
('2023-01-01 08:15:00', 1, 11.25),
('2023-01-01 08:20:00', 1, 10.90),
('2023-01-01 08:25:00', 1, 11.10),
('2023-01-01 08:30:00', 1, 11.00),
('2023-01-01 08:35:00', 1, 10.80),
('2023-01-01 08:40:00', 1, 11.20),
('2023-01-01 08:45:00', 1, 11.30);
-------------------------------------------------
-- Region: 1. Basic Time Window Queries
-------------------------------------------------
/*
1.1 Return readings for SensorID = 1 during the morning window.
*/
SELECT *
FROM time_series_data
WHERE sensor_id = 1
AND reading_time BETWEEN '2023-01-01 08:00:00' AND '2023-01-01 09:00:00'
ORDER BY reading_time;
-------------------------------------------------
-- Region: 2. Time Series Analysis Using Window Functions
-------------------------------------------------
/*
2.1 Running total of readings by time.
*/
SELECT
reading_id,
reading_time,
sensor_id,
reading_value,
SUM(reading_value) OVER (
PARTITION BY sensor_id
ORDER BY reading_time
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS running_total
FROM time_series_data
ORDER BY reading_time;
/*
2.2 Three-point moving average.
*/
SELECT
reading_id,
reading_time,
sensor_id,
reading_value,
AVG(reading_value) OVER (
PARTITION BY sensor_id
ORDER BY reading_time
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
) AS moving_average
FROM time_series_data
ORDER BY reading_time;
/*
2.3 Previous, next, and difference values.
*/
SELECT
reading_id,
reading_time,
sensor_id,
reading_value,
LAG(reading_value, 1) OVER (PARTITION BY sensor_id ORDER BY reading_time) AS previous_value,
LEAD(reading_value, 1) OVER (PARTITION BY sensor_id ORDER BY reading_time) AS next_value,
reading_value - LAG(reading_value, 1) OVER (PARTITION BY sensor_id ORDER BY reading_time) AS value_difference
FROM time_series_data
ORDER BY reading_time;
-------------------------------------------------
-- Region: 3. Grouping by Fixed Intervals
-------------------------------------------------
/*
3.1 Bucket readings into 15-minute windows.
*/
SELECT
FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(reading_time) / 900) * 900) AS time_interval,
COUNT(*) AS reading_count,
AVG(reading_value) AS avg_value,
MIN(reading_value) AS min_value,
MAX(reading_value) AS max_value
FROM time_series_data
GROUP BY FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(reading_time) / 900) * 900)
ORDER BY time_interval;
-------------------------------------------------
-- Region: 4. Manual History Tracking
-------------------------------------------------
/*
4.1 Update one reading to generate a history row.
*/
UPDATE time_series_data
SET reading_value = 11.70
WHERE reading_id = 1;
/*
4.2 Review the current data and the captured change history.
*/
SELECT *
FROM time_series_data
ORDER BY reading_id;
SELECT *
FROM time_series_history
ORDER BY changed_at;
-------------------------------------------------
-- Region: End of Script
-------------------------------------------------