How do I get a list of numbers in MySQL?
I have a database of films and I would like to have a list of years when I do not have a movie this year. So all I need is a list (1900 .. 2012) and then I can JOIN AND SIGN IN AND NOT SIGN IN to whatever I want.
I have:
CREATE PROCEDURE build_years(p1 SMALLINT)
BEGIN
CREATE TEMPORARY TABLE year (year SMALLINT(5) UNSIGNED);
label1: LOOP
INSERT INTO year VALUES (p1);
SET p1 = p1 + 1;
IF p1 > 2012 THEN LEAVE label1; END IF;
END LOOP;
END
But it looks like this unSQL and only marginally less kludgy and then runs Python code to create the same table. I would really love the fact that it didn't use a stored procedure, didn't use a loop, and didn't use the actual table in that order.
source to share
I had a similar problem a few years ago. My solution was:
1. Sequence table
I created a table filled with an integer sequence from 0 to <as needed>:
CREATE TABLE numbers (n INT);
INSERT INTO numbers VALUES (0),(1),(2),(3),(4);
INSERT INTO numbers SELECT n+5 FROM numbers;
INSERT INTO numbers SELECT n+10 FROM numbers;
INSERT INTO numbers SELECT n+20 FROM numbers;
INSERT INTO numbers SELECT n+40 FROM numbers;
etc.
It is executed only once, so it can even be created manually from outside your application.
2. Select the data type and range required
For integers this is obvious - that is, the range is 1.99:
SELECT n FROM numbers WHERE n BETWEEN 1 AND 99;
Dates - from 2 to 2 days:
SELECT date_add(now(),INTERVAL 2*n HOUR) FROM numbers WHERE n BETWEEN 0 AND 23;
So, in your case, it could be:
SELECT n+1900 AS n_year FROM numbers WHERE n BETWEEN 0 AND 112;
Then JOIN
on n_year
.
source to share
This should work until you need more than 195 years, after which you will need to add UNION ALL
:
SELECT Year
FROM ( SELECT @i:= @i + 1 AS YEAR
FROM INFORMATION_SCHEMA.COLLATION_CHARACTER_SET_APPLICABILITY,
( SELECT @i:= 1899) AS i
) As Y
WHERE Year BETWEEN 1900 AND 2012
ORDER BY Year;
Although I am assuming the COLLATION_CHARACTER_SET_APPLICABILITY
System table has a default size of 195 based on my reliable SQL Fiddle test site
source to share
This will return a list from 2012 to 1900 if you really want to store it in the query.
SELECT
TO_CHAR (ADD_MONTHS (TRUNC (SYSDATE, 'YYYY'), ((rno - 1) * -12)), 'YYYY') AS "years"
FROM
(
SELECT
LEVEL rno
FROM DUAL
CONNECT BY LEVEL <=
(SELECT TO_CHAR (TRUNC (SYSDATE, 'YYYY'), 'YYYY')
- 1899
yearstobuild
FROM DUAL))
source to share
Using this general query is faster:
INSERT INTO numbers SELECT n+(SELECT COUNT(*) FROM numbers) FROM numbers;
The execution of each request is duplicated:
INSERT INTO numbers VALUES (0),(1),(2),(3),(4);
INSERT INTO numbers SELECT n+(SELECT COUNT(*) FROM numbers) FROM numbers;
INSERT INTO numbers SELECT n+(SELECT COUNT(*) FROM numbers) FROM numbers;
INSERT INTO numbers SELECT n+(SELECT COUNT(*) FROM numbers) FROM numbers;
...
source to share