snippetsqlMinor
How can I get dates that wrap around new year from non-datetime columns?
Viewed 0 times
aroundcannewyearnoncolumnsdatesgetthathow
Problem
I have a table in my MySQL database that stores daily data (an entry for each day of the year), but does not use a
Say I then want to get the values from this table from a certain date, like 01 Dec 2015 to 60 days from then, which would be 30 Jan 2016. Is there a way to get back the date and value for all of those days, working okay across the new year? Ideally I'd love results that flow like:
(hopefully you get the idea).
If you can think of a better way to store this static daily data so that I can achieve the above goal, I'm open to that as well! Thanks for your help!
DATETIME column for this. This is because the data is the same for every year (it's climatology data, so the "normal" high temperature for Jan 7, 2015 is the same as for Jan 7, 2016 and so on). I have three fields that represent the day this data is valid for, so my table looks like:month, day_of_month, day_of_year, value
1 1 1 23
1 2 2 22.95
...
12 31 365 23.12Say I then want to get the values from this table from a certain date, like 01 Dec 2015 to 60 days from then, which would be 30 Jan 2016. Is there a way to get back the date and value for all of those days, working okay across the new year? Ideally I'd love results that flow like:
valid_date, value
...
2015-12-31 23.12
2016-01-01 23
2016-01-02 22.95
...(hopefully you get the idea).
If you can think of a better way to store this static daily data so that I can achieve the above goal, I'm open to that as well! Thanks for your help!
Solution
You can use
Test:
You can try it in this Fiddle.
EDIT:
According of what you want, you can make it with pure SQL:
Query Meaning:
```
SELECT
v.selected_date,
v.dayyear,
c.value AS DayValue,
c.day_of_year
FROM test.cli_table AS c
--- > This JOIN is generating all the dates between the selected_dates ('2015-12-25' AND '2016-01-03')
JOIN (SELECT
adddate('1970-01-01',t4.i10000 + t3.i1000 + t2.i100 + t1.i10 + t0.i) AS selected_date,
DAYOFYEAR(adddate('1970-01-01',t4.i10000 + t3.i1000 + t2.i100 + t1.i10 + t0.i)) AS dayyear
FROM
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) AS v
--- > Here I'm matching every dayyear of the generated d
MAKEDATE(), it makes the day_of_year to a date.Test:
mysql> SELECT * FROM cli_table;
+-------+--------------+-------------+-------+
| month | day_of_month | day_of_year | value |
+-------+--------------+-------------+-------+
| 1 | 1 | 1 | 23.00 |
| 1 | 2 | 2 | 22.95 |
| 12 | 31 | 365 | 23.12 |
+-------+--------------+-------------+-------+
3 rows in set (0.00 sec)
mysql> SELECT
-> MAKEDATE(YEAR(CURDATE()),day_of_year) AS Date,
-> value AS DayValue
-> FROM test.cli_table;
+------------+----------+
| Date | DayValue |
+------------+----------+
| 2015-01-01 | 23.00 |
| 2015-01-02 | 22.95 |
| 2015-12-31 | 23.12 |
+------------+----------+
3 rows in set (0.00 sec)
mysql>You can try it in this Fiddle.
EDIT:
According of what you want, you can make it with pure SQL:
mysql> SELECT * FROM test.cli_table;
+-------+--------------+-------------+-------+
| month | day_of_month | day_of_year | value |
+-------+--------------+-------------+-------+
| 1 | 1 | 1 | 5.00 |
| 1 | 2 | 2 | 6.00 |
| 1 | 3 | 3 | 7.00 |
| 12 | 25 | 359 | 23.00 |
| 12 | 26 | 360 | 22.95 |
| 12 | 27 | 361 | 1.00 |
| 12 | 28 | 362 | 2.00 |
| 12 | 29 | 363 | 3.00 |
| 12 | 30 | 364 | 4.00 |
| 12 | 31 | 365 | 23.12 |
+-------+--------------+-------------+-------+
10 rows in set (0.00 sec)
mysql> SELECT
-> v.selected_date,
-> v.dayyear,
-> c.value AS DayValue,
-> c.day_of_year
-> FROM test.cli_table AS c
-> JOIN (SELECT
-> adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) AS selected_date,
-> DAYOFYEAR(adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i)) AS dayyear
-> FROM
-> (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
-> (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
-> (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
-> (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
-> (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) AS v
-> ON (v.selected_date between '2015-12-25' AND '2016-01-03'
-> AND v.dayyear=c.day_of_year);
+---------------+---------+----------+-------------+
| selected_date | dayyear | DayValue | day_of_year |
+---------------+---------+----------+-------------+
| 2015-12-25 | 359 | 23.00 | 359 |
| 2015-12-26 | 360 | 22.95 | 360 |
| 2015-12-27 | 361 | 1.00 | 361 |
| 2015-12-28 | 362 | 2.00 | 362 |
| 2015-12-29 | 363 | 3.00 | 363 |
| 2015-12-30 | 364 | 4.00 | 364 |
| 2015-12-31 | 365 | 23.12 | 365 |
| 2016-01-01 | 1 | 5.00 | 1 |
| 2016-01-02 | 2 | 6.00 | 2 |
| 2016-01-03 | 3 | 7.00 | 3 |
+---------------+---------+----------+-------------+
10 rows in set (0.00 sec)
mysql>Query Meaning:
```
SELECT
v.selected_date,
v.dayyear,
c.value AS DayValue,
c.day_of_year
FROM test.cli_table AS c
--- > This JOIN is generating all the dates between the selected_dates ('2015-12-25' AND '2016-01-03')
JOIN (SELECT
adddate('1970-01-01',t4.i10000 + t3.i1000 + t2.i100 + t1.i10 + t0.i) AS selected_date,
DAYOFYEAR(adddate('1970-01-01',t4.i10000 + t3.i1000 + t2.i100 + t1.i10 + t0.i)) AS dayyear
FROM
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) AS v
--- > Here I'm matching every dayyear of the generated d
Code Snippets
mysql> SELECT * FROM cli_table;
+-------+--------------+-------------+-------+
| month | day_of_month | day_of_year | value |
+-------+--------------+-------------+-------+
| 1 | 1 | 1 | 23.00 |
| 1 | 2 | 2 | 22.95 |
| 12 | 31 | 365 | 23.12 |
+-------+--------------+-------------+-------+
3 rows in set (0.00 sec)
mysql> SELECT
-> MAKEDATE(YEAR(CURDATE()),day_of_year) AS Date,
-> value AS DayValue
-> FROM test.cli_table;
+------------+----------+
| Date | DayValue |
+------------+----------+
| 2015-01-01 | 23.00 |
| 2015-01-02 | 22.95 |
| 2015-12-31 | 23.12 |
+------------+----------+
3 rows in set (0.00 sec)
mysql>mysql> SELECT * FROM test.cli_table;
+-------+--------------+-------------+-------+
| month | day_of_month | day_of_year | value |
+-------+--------------+-------------+-------+
| 1 | 1 | 1 | 5.00 |
| 1 | 2 | 2 | 6.00 |
| 1 | 3 | 3 | 7.00 |
| 12 | 25 | 359 | 23.00 |
| 12 | 26 | 360 | 22.95 |
| 12 | 27 | 361 | 1.00 |
| 12 | 28 | 362 | 2.00 |
| 12 | 29 | 363 | 3.00 |
| 12 | 30 | 364 | 4.00 |
| 12 | 31 | 365 | 23.12 |
+-------+--------------+-------------+-------+
10 rows in set (0.00 sec)
mysql> SELECT
-> v.selected_date,
-> v.dayyear,
-> c.value AS DayValue,
-> c.day_of_year
-> FROM test.cli_table AS c
-> JOIN (SELECT
-> adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) AS selected_date,
-> DAYOFYEAR(adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i)) AS dayyear
-> FROM
-> (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
-> (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
-> (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
-> (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
-> (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) AS v
-> ON (v.selected_date between '2015-12-25' AND '2016-01-03'
-> AND v.dayyear=c.day_of_year);
+---------------+---------+----------+-------------+
| selected_date | dayyear | DayValue | day_of_year |
+---------------+---------+----------+-------------+
| 2015-12-25 | 359 | 23.00 | 359 |
| 2015-12-26 | 360 | 22.95 | 360 |
| 2015-12-27 | 361 | 1.00 | 361 |
| 2015-12-28 | 362 | 2.00 | 362 |
| 2015-12-29 | 363 | 3.00 | 363 |
| 2015-12-30 | 364 | 4.00 | 364 |
| 2015-12-31 | 365 | 23.12 | 365 |
| 2016-01-01 | 1 | 5.00 | 1 |
| 2016-01-02 | 2 | 6.00 | 2 |
| 2016-01-03 | 3 | 7.00 | 3 |
+---------------+---------+----------+-------------+
10 rows in set (0.00 sec)
mysql>SELECT
v.selected_date,
v.dayyear,
c.value AS DayValue,
c.day_of_year
FROM test.cli_table AS c
--- > This JOIN is generating all the dates between the selected_dates ('2015-12-25' AND '2016-01-03')
JOIN (SELECT
adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) AS selected_date,
DAYOFYEAR(adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i)) AS dayyear
FROM
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) AS v
--- > Here I'm matching every dayyear of the generated dates with the cli_table.day_of_year.
ON (v.selected_date between '2015-12-25' AND '2016-01-03'
AND v.dayyear=c.day_of_year);Context
StackExchange Database Administrators Q#121051, answer score: 2
Revisions (0)
No revisions yet.