generate_series() equivalent in MySQL
This is how I do it. It creates a range of dates from 2011-01-01 to 2011-12-31:
select
date_format(
adddate('2011-1-1', @num:=@num+1),
'%Y-%m-%d'
) date
from
any_table,
(select @num:=-1) num
limit
365
-- use limit 366 for leap years if you're putting this in production
The only requirement is that the number of rows in any_table should be greater or equal to the size of the needed range (>= 365 rows in this example). You will most likely use this as a subquery of your whole query, so in your case any_table can be one of the tables you use in that query.
generate_series in MySQL
Here is the concept, but I don't have mySQL installed on this box. You will need to create a table of integers, using AUTO INCREMENT. A table of numbers is generally a handy table to have available in a database, and would only need be created once
create table NumberList (id MEDIUMINT NOT NULL AUTO_INCREMENT,fill char(1))
declare @x INT
set @x=0
while @x < 20
begin
insert into numberList values(null)
Set @x = @x+1
end
Then, join this table as shown below using the LIMIT clause
select substr('somestring',id)
from numberlist
limit len('somestring')
I wrote this in SQL server, but it shouldn't be too difficult to convert to mySQL...
The code below SHOULD work in mySQL
DECLARE xx INT DEFAULT 0;
WHILE xx < 20 DO
insert into numberList values(null)
SET xx = xx + 1;
END WHILE;
Generate an integer sequence in MySQL
There is no sequence number generator (CREATE SEQUENCE) in MySQL. Closest thing is AUTO_INCREMENT
, which can help you construct the table.
How do I make a row generator in MySQL?
Hate to say this, but MySQL
is the only RDBMS
of the big four that doesn't have this feature.
In Oracle
:
SELECT *
FROM dual
CONNECT BY
level < n
In MS SQL
(up to 100
rows):
WITH hier(row) AS
(
SELECT 1
UNION ALL
SELECT row + 1
FROM hier
WHERE row < n
)
SELECT *
FROM hier
or using hint up to 32768
WITH hier(row) AS
(
SELECT 1
UNION ALL
SELECT row + 1
FROM hier
WHERE row < 32768
)
SELECT *
FROM hier
OPTION (MAXRECURSION 32767) -- 32767 is the maximum value of the hint
In PostgreSQL
:
SELECT *
FROM generate_series (1, n)
In MySQL
, nothing.
Generating time series reports
Let's say you have a gigantic table measure
with two columns datestamp
and temp
.
Let's say you want to see the temperature every six minutes (10x per hour) for the last week. You can do this sort of thing. We'll get to defining trunc
in a moment.
SELECT trunc(datestamp) datestamp, AVG(temp) temp
FROM measure
WHERE datestamp >= CURDATE() - INVERVAL 7 DAY
GROUP BY trunc(datestamp)
ORDER BY trunc(datestamp)
That works for any reasonable definition of trunc
. In this case trunc(t)
returns the beginning of the six-minute period in which t
occurs. So, trunc('1942-12-07 08:45:17')
gives 1942-12-07 08:42:00
).
Here's a query that works for every six minute interval.
SELECT DATE_FORMAT(datestamp,'%Y-%m-%d %H:00') +
INTERVAL (MINUTE(datestamp) -
MINUTE(datestamp) MOD 6) datestamp,
AVG(temp) temp
FROM measure
WHERE datestamp >= CURDATE() - INVERVAL 7 DAY
GROUP BY DATE_FORMAT(datestamp,'%Y-%m-%d %H:00') +
INTERVAL (MINUTE(datestamp) -
MINUTE(datestamp) MOD 6)
ORDER BY 1
This uses inbuilt date arithmetic rather than unix timestamp arithmetic.
You can use a stored function to make this easier to read.
DELIMITER $$
DROP FUNCTION IF EXISTS TRUNC_N_MINUTES$$
CREATE
FUNCTION TRUNC_N_MINUTES(datestamp DATETIME, n INT)
RETURNS DATETIME DETERMINISTIC NO SQL
COMMENT 'truncate to N minute boundary. For example,
TRUNCATE_N_MINUTES(sometime, 15) gives the nearest
preceding quarter hour'
RETURN DATE_FORMAT(datestamp,'%Y-%m-%d %H:00') +
INTERVAL (MINUTE(datestamp) -
MINUTE(datestamp) MOD n) MINUTE$$
DELIMITER ;
Then your query will say
SELECT TRUNC_N_MINUTES(datestamp, 6) datestamp, AVG(temp) temp
FROM measure
WHERE datestamp >= CURDATE() - INVERVAL 7 DAY
GROUP BY TRUNC_N_MINUTES(datestamp, 6)
ORDER BY TRUNC_N_MINUTES(datestamp, 6)
If you want to summarize by 5, 10, 15, or minute boundaries (three items per hour) simply use that number in place of 6
.
You'll need different trunc()
functions for hours, etc.
The trunc()
function for daily summaries is DATE(datestamp)
.
For monthly summaries it is LAST_DAY(datestamp)
. For example,
SELECT LAST_DAY(datestamp) month_ending, AVG(temp) temp
FROM measure
GROUP BY LAST_DAY(datestamp)
ORDER BY LAST_DAY(datestamp)
yields a month-by-month summary.
Related Topics
Difference Between "Read Commited" and "Repeatable Read"
Select Statement to Find Duplicates on Certain Fields
What Are Best Practices For Multi-Language Database Design
Database Structure For Tree Data Structure
SQL Query to Return Differences Between Two Tables
How to Dump the Data of Some Sqlite3 Tables
Efficient Way to Implement Paging
Select Count(*) from Multiple Tables
Get Day of Week in SQL Server 2005/2008
Check If MySQL Table Exists Without Using "Select From" Syntax
How to Force Postgres to Use a Particular Index
How to Do a Case Sensitive Search in Where Clause (I'M Using SQL Server)
How to Use Variables in Oracle SQL Developer
How to Select from Subquery Using Laravel Query Builder
MySQL Delete from With Subquery as Condition
How to Select Unique Records by Sql