I have a table field, let's call it pattern containing a list of comma separated values.
For example: '10,20,30,40,50'
I need to select * from said table, where at least one element from another similar string appears in that field too.
For example, say I have the string '10,50,70' A record whose pattern field is '10,20,30,50,70' should be selected, because 10 and 70 are present in '10,50,70'.`
Is there any way of doing this, except lots of OR where i check if pattern LIKE '%10%' OR pattern LIKE %50% OR pattern LIKE %70% ?
You can use FIND_IN_SET() as an alternative like below though as already suggested in comment, consider Normalizing your table.
SELECT * FROM table_name
WHERE FIND_IN_SET('10','10,20,30,50,70')
OR FIND_IN_SET('50','10,20,30,50,70')
OR FIND_IN_SET('70','10,20,30,50,70') ;
As mentioned by Patrick Hofman, normalising the database is the best solution.
If you really must stick with such a table layout then there are a couple of solutions.
You can split up the comma separated values and join the results based on that. Not that the cross joined tables are just generating a range of numbers (in this case 0 to 99), but this must equal or exceed the max number of delimited values. It will also be slow as no indexes can be used. Also large numbers of records are generated in memory to do this calculation.
Something like this:-
SELECT DISTINCT sub0.id, sub1.id
FROM
(
SELECT DISTINCT id, SUBSTRING_INDEX(SUBSTRING_INDEX(pattern, ',', units.i + tens.i * 10), ',' -1) AS pattern_id
FROM some_table
CROSS JOIN (SELECT 1 AS i UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0) units
CROSS JOIN (SELECT 1 AS i UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0) tens
) sub0
INNER JOIN
(
SELECT DISTINCT id, SUBSTRING_INDEX(SUBSTRING_INDEX(pattern, ',', units.i + tens.i * 10), ',' -1) AS pattern_id
FROM some_table
CROSS JOIN (SELECT 1 AS i UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0) units
CROSS JOIN (SELECT 1 AS i UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0) tens
) sub1
ON sub0.pattern_id = sub1.pattern_id
AND sub0.id != sub1.id
If the comma separated value is the key to another table then you could maybe do a couple of joins based on FIND_IN_SET.
SELECT DISTINCT a.*, b.*
FROM some_table a
INNER JOIN some_patterns b
ON FIND_IN_SET(b.id, a.patterns)
INNER JOIN some_table c
ON FIND_IN_SET(b.id, c.patterns)
In reality it would probably be best to normalise you database, possibly using SQL based on these solutions just to help you extract the data to your new normalised format
I've inherited this method of storing small lists of integers and wrote the included function to rotate CSV of integers into a column.
CREATE function [dbo].[udf_IntegerColumnFromCSV] ( #DelimStr nvarchar(max) )
returns #ListOfInts table ( Value int )
AS
BEGIN
set #DelimStr = #DelimStr + ',' -- add one more to the end
declare #i int -- the "start" of the next value to be read
declare #j int -- the location of the next comma
declare #le int -- line end
set #i = 1
set #j = 1
set #le = len(#DelimStr)
while ( #j < #le ) begin
set #j = charindex( ',', #DelimStr, #i ) -- find the end of the next row
insert into #ListOfInts (Value) values ( cast(substring( #DelimStr, #i, #j-#i ) as integer) )
set #i = #j + 1
end
return
end
In a situation where you have a list of values stored as CSV:
select ID, ValueList from TableX
ID : ValueList
20 : 38, 39, 40, 41, 42, 44, 61,62,63,64,65,66, 70,71,72
21 : 12
22 : 61,62,63,64,65,66
Use the function to pivot the values into a column:
select ID, vl.* from TableX cross apply dbo.udf_IntegerColumnFromCSV(ValueList) vl
20: 38
20: 39
20: 40
20: 41
20: 42
20: 44
20: 61
20: 62
20: 63
20: 64
20: 65
20: 66
20: 70
20: 71
20: 72
21: 12
22: 61
22: 62
22: 63
22: 64
22: 65
22: 66
Related
Users table has id field in mysql database, and table has below record in id field
|id|
2
3
5
6
9
10
15
16
18
21
25
I want to get missing records row like below:-
1
4
7
8
11
12
13
14
17
19
20
22
23
24
How cool is this ?
SELECT seq.`id` FROM (
SELECT #row := #row + 1 as `id`
FROM `users` t, (SELECT #row := 0) r
CROSS JOIN `users` t2
) as seq WHERE seq.`id` NOT IN (SELECT `id` FROM `users`)
AND seq.`id` <= (SELECT max(`id`) from `users`);
If you want the missing ids for analytical purpose, should love this one:
SELECT CONCAT(dt.missing, IF(dt.`found`-1 > dt.missing, CONCAT(' to ', dt.`found` - 1), '')) AS missing
FROM ( SELECT #rownum:=#rownum+1 AS `missing`,
IF (#rownum=id, 0, #rownum:=id) AS `found`
FROM ( SELECT #rownum:=0 ) AS r
JOIN users
ORDER BY id ) AS dt
WHERE dt.`found`!= 0;
Use a calendar table approach and anti-join approach:
CREATE TABLE nums (id INT);
INSERT INTO nums (id)
(
SELECT (t*10+u+1) x FROM
(SELECT 0 t 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) A,
(SELECT 0 u 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) B
);
SELECT
n.id
FROM nums n
LEFT JOIN users u
ON n.id = u.id
WHERE
u.id IS NULL
ORDER BY
n.id;
Demo
Note that in the demo and query I did not limit the height of the range of missing numbers which gets returned. I arbitrarily used a sequence of numbers 1..100, but you may restrict to any size you want.
I'm trying to extract hashtags from a field using REGEXP in sql. Right now I'm doing this query
SELECT caption FROM posts WHERE caption REGEXP "#[a-zA-Z0-9_]+"
But i want to extract that specific word which was matched by this pattern.
Like if i have following entry in my database
id caption user
1 #hi i'm here 2
2 hello #hi there 3
3 i'm x #hi 4
4 I'm #Driving 2
5 I #love #food 6
Right now my query is returning
caption
#hi i'm here
hello #hi there
i'm x #hi
I'm #Driving
I #love #food
But I want
tag
#hi
#Driving
#love
#food
How can i achieve this.
Thanks for your help.
Create table/insert data
CREATE TABLE Table1
(`id` INT, `caption` VARCHAR(255), `user` INT)
;
INSERT INTO Table1
(`id`, `caption`, `user`)
VALUES
(1, '#hi i''m here', 2),
(2, 'hello #hi there', 3),
(3, 'i''m x #hi', 4),
(4, 'I''m #Driving', 2),
(5, 'I #love #food', 6)
;
You can split the words in caption with SUBSTRING_INDEX(SUBSTRING_INDEX(caption, ' ', 1), ' ', -1) to get the first word SUBSTRING_INDEX(SUBSTRING_INDEX(caption, ' ', 2), ' ', -1) to get the second word.
But how to make it dynamic so you larger number of words can splitted.
First you make a number generator with SQL.
This query will generate a list of number from 1 to 100
Query
SELECT
#number := #number + 1 AS number
FROM (
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) row1
CROSS JOIN
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) row2
CROSS JOIN
(SELECT #number:=0) AS init_user_params
)
Result
number
--------
1
2
3
4
5
6
7
8
9
10
...
...
90
91
92
93
94
95
96
97
98
99
100
Now we can CROSS JOIN our number generated list with our Table1 (in our example)
This will generate (table count) * 100 records with duplicated records.
And use the generated numbers list with in SUBSTRING_INDEX(SUBSTRING_INDEX(caption, ' ', [word offset]), ' ', -1) like so
Query
SELECT
DISTINCT #remove duplicates
SUBSTRING_INDEX(SUBSTRING_INDEX(caption, ' ', numbers.number), ' ', -1) AS tag
FROM (
SELECT
#number := #number + 1 AS number
FROM (
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) row1
CROSS JOIN
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) row2
CROSS JOIN
(SELECT #number:=0) AS init_user_params
)
)
AS numbers
CROSS JOIN Table1
WHERE
SUBSTRING_INDEX(SUBSTRING_INDEX(caption, ' ', numbers.number), ' ', -1) LIKE '#%' #we only want words starting with #
ORDER BY
Table1.id ASC
Result
tag
----------
#hi
#Driving
#love
#food
Notes
This query only works when caption have equal to 100 words or less
This query is pretty fast on smaller sized tables. On larger tables this won't scale well because off the CROSS JOIN
You really should have a table where you store the hashtags.
This query
SELECT user_Id,CAST(leave_dates_object AS CHAR(10000) CHARACTER SET utf8) AS LeaveDates
FROM `lms_leaves`
returns
Now I want three rows user_Id and Date and F_or_H from the formatted string return from leave date.
I modified and tried code from this link but can't able to get result.
Expected Output
user_Id Date LeaveType
85 2016-09-06 F
85 2016-09-07 F
85 2016-09-06 H
63 2016-03-25 F
63 2016-03-02 F
63 2016-03-03 H
Please Help me.
Suppose you have maximally 8 dates in one record:
create table users (userId int not null, leaveDates varchar(1000) not null);
INSERT users (userId,leaveDates) VALUES (85,'--- \r-2016-09-06:F\r-2016-09-07:F'),(85,'---\r-2016-09-06:H'),(63,'---\r-2016-03-25:F'),(63,'---\r-2016-03-02:F\r-2016-03-03:H');
SELECT s.userId AS userId,LEFT(s.leaveDate,CHAR_LENGTH(s.leaveDate)-2) AS ldate, RIGHT(s.leaveDate,1) AS lflag
FROM (
SELECT
u.userId,
REPLACE(SUBSTRING(SUBSTRING_INDEX(u.leaveDates, '\r-', n.number),
CHAR_LENGTH(SUBSTRING_INDEX(u.leaveDates, '\r-', n.number -1)) + 1),
'\r-', '') as leaveDate
FROM (SELECT u0.userId,REPLACE(u0.leaveDates,'---','') AS leaveDates FROM users u0) u
INNER JOIN (SELECT 1 AS number UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8) n
ON (char_length(u.leaveDates) - char_length(replace(u.leaveDates, '\r-', '')) >= n.number-1)) s
WHERE s.leaveDate<>''
ORDER BY userId,ldate,lflag;
I have the table "words":
id
name
insert into words values(null, 'one');
insert into words values(null, 'two');
insert into words values(null, 'three');
I need to find out, distinctly, the letters used across all over the table.
In this case the result would be:
o
n
e
t
w
h
r
I actually dont really have a clue on how to do this. I found some stored procedure that seems to solve it. Some kind of iteration through all the rows where new letters are added to the final results.
Is there a way to do this with a pure sql-command?
You could use SUBSTRING with derived tally table:
SELECT DISTINCT SUBSTRING(word, n, 1) AS letter
FROM words w
CROSS JOIN
(
SELECT a.N + b.N * 10 + c.N * 1000 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) c
) n
WHERE n <= LENGTH(w.word)
ORDER BY letter;
SqlFiddleDemo
If you need o and O as different letters add COLLATE utf8_bin:
SELECT DISTINCT SUBSTRING(word, n, 1) COLLATE utf8_bin AS letter
How do I generate a range of consecutive numbers (one per line) from a MySQL query so that I can insert them into a table?
For example:
nr
1
2
3
4
5
I would like to use only MySQL for this (not PHP or other languages).
Here is one way to do it set-based without loops. This can also be made into a view for re-use. The example shows the generation of a sequence from 0 through 999, but of course, it may be modified to suit.
INSERT INTO
myTable
(
nr
)
SELECT
SEQ.SeqValue
FROM
(
SELECT
(HUNDREDS.SeqValue + TENS.SeqValue + ONES.SeqValue) SeqValue
FROM
(
SELECT 0 SeqValue
UNION ALL
SELECT 1 SeqValue
UNION ALL
SELECT 2 SeqValue
UNION ALL
SELECT 3 SeqValue
UNION ALL
SELECT 4 SeqValue
UNION ALL
SELECT 5 SeqValue
UNION ALL
SELECT 6 SeqValue
UNION ALL
SELECT 7 SeqValue
UNION ALL
SELECT 8 SeqValue
UNION ALL
SELECT 9 SeqValue
) ONES
CROSS JOIN
(
SELECT 0 SeqValue
UNION ALL
SELECT 10 SeqValue
UNION ALL
SELECT 20 SeqValue
UNION ALL
SELECT 30 SeqValue
UNION ALL
SELECT 40 SeqValue
UNION ALL
SELECT 50 SeqValue
UNION ALL
SELECT 60 SeqValue
UNION ALL
SELECT 70 SeqValue
UNION ALL
SELECT 80 SeqValue
UNION ALL
SELECT 90 SeqValue
) TENS
CROSS JOIN
(
SELECT 0 SeqValue
UNION ALL
SELECT 100 SeqValue
UNION ALL
SELECT 200 SeqValue
UNION ALL
SELECT 300 SeqValue
UNION ALL
SELECT 400 SeqValue
UNION ALL
SELECT 500 SeqValue
UNION ALL
SELECT 600 SeqValue
UNION ALL
SELECT 700 SeqValue
UNION ALL
SELECT 800 SeqValue
UNION ALL
SELECT 900 SeqValue
) HUNDREDS
) SEQ
Here's a hardware engineer's version of Pittsburgh DBA's solution:
SELECT
(TWO_1.SeqValue + TWO_2.SeqValue + TWO_4.SeqValue + TWO_8.SeqValue + TWO_16.SeqValue) SeqValue
FROM
(SELECT 0 SeqValue UNION ALL SELECT 1 SeqValue) TWO_1
CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 2 SeqValue) TWO_2
CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 4 SeqValue) TWO_4
CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 8 SeqValue) TWO_8
CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 16 SeqValue) TWO_16;
If you need the records in a table and you want to avoid concurrency issues, here's how to do it.
First you create a table in which to store your records
CREATE TABLE `incr` (
`Id` int(11) NOT NULL auto_increment,
PRIMARY KEY (`Id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Secondly create a stored procedure like this:
DELIMITER ;;
CREATE PROCEDURE dowhile()
BEGIN
DECLARE v1 INT DEFAULT 5;
WHILE v1 > 0 DO
INSERT incr VALUES (NULL);
SET v1 = v1 - 1;
END WHILE;
END;;
DELIMITER ;
Lastly call the SP:
CALL dowhile();
SELECT * FROM incr;
Result
Id
1
2
3
4
5
Let's say you want to insert numbers 1 through 100 into your table. As long as you have some other table that has at least that many rows (doesn't matter the content of the table), then this is my preferred method:
INSERT INTO pivot100
SELECT #ROW := #ROW + 1 AS ROW
FROM someOtherTable t
join (SELECT #ROW := 0) t2
LIMIT 100
;
Want a range that starts with something other than 1? Just change what #ROW gets set to on the join.
As you all understand, this is rather hacky so use with care
SELECT
id % 12 + 1 as one_to_twelve
FROM
any_large_table
GROUP BY
one_to_twelve
;
DECLARE i INT DEFAULT 0;
WHILE i < 6 DO
/* insert into table... */
SET i = i + 1;
END WHILE;
Very similar to the accepted response, but using the new WITH syntax for mysql >= 8.0 which makes a lot more legible and the intent is also clearer
WITH DIGITS (N) AS (
SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL
SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL
SELECT 8 UNION ALL SELECT 9)
SELECT
UNITS.N + TENS.N*10 + HUNDREDS.N*100 + THOUSANDS.N*1000
FROM
DIGITS AS UNITS, DIGITS AS TENS, DIGITS AS HUNDREDS, DIGITS AS THOUSANDS;
In MariaDB you can do:
SELECT * FROM seq_i_to_N
For example:
SELECT * FROM seq_0_to_1000
SELECT * FROM seq_1_to_1000000
Reference: https://www.percona.com/blog/2020/07/27/generating-numeric-sequences-in-mysql/
The "shortest" way i know (in MySQL) to create a table with a long sequence is to (cross) join an existing table with itself. Since any (common) MySQL server has the information_schema.COLUMNS table i would use it:
DROP TABLE IF EXISTS seq;
CREATE TABLE seq (i MEDIUMINT AUTO_INCREMENT PRIMARY KEY)
SELECT NULL AS i
FROM information_schema.COLUMNS t1
JOIN information_schema.COLUMNS t2
JOIN information_schema.COLUMNS t3
LIMIT 100000; -- <- set your limit here
Usually one join should be enough to create over 1M rows - But one more join will not hurt :-) - Just don't forget to set a limit.
If you want to include 0, you should "remove" the AUTO_INCEMENT property.
ALTER TABLE seq ALTER i DROP DEFAULT;
ALTER TABLE seq MODIFY i MEDIUMINT;
Now you can insert 0
INSERT INTO seq (i) VALUES (0);
and negative numbers as well
INSERT INTO seq (i) SELECT -i FROM seq WHERE i <> 0;
You can validate the numbers with
SELECT MIN(i), MAX(i), COUNT(*) FROM seq;
All other answers are good, however they all have speed issues for larger ranges because they force MySQL to generate every number then filter them.
The following only makes MySQL generate the numbers that are needed, and therefore is faster:
set #amount = 55; # How many numbers from zero you want to generate
select `t0`.`i`+`t1`.`i`+`t2`.`i`+`t3`.`i` as `offset`
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 10 union select 20 union select 30 union select 40 union select 50 union select 60 union select 70 union select 80 union select 90) `t1`,
(select 0 `i` union select 100 union select 200 union select 300 union select 400 union select 500 union select 600 union select 700 union select 800 union select 900) `t2`,
(select 0 `i` union select 1000 union select 2000 union select 3000 union select 4000 union select 5000 union select 6000 union select 7000 union select 8000 union select 9000) `t3`
where `t3`.`i`<#amount
and `t2`.`i`<#amount
and `t1`.`i`<#amount
and `t0`.`i`+`t1`.`i`+`t2`.`i`+`t3`.`i`<#amount;
With the above you can generate upto 10,000 numbers (0 to 9,999) with no slower speed overhead for lower numbers, regardless how low they are.
Here's a way to do it with json_table if you have MySql 8 and above:
set #noRows = 100;
SELECT tt.rowid - 1 AS value
FROM JSON_TABLE(CONCAT('[{}', REPEAT(',{}', #noRows - 1), ']'),
"$[*]" COLUMNS(rowid FOR ORDINALITY)
) AS tt;
(h/t - https://www.percona.com/blog/2020/07/27/generating-numeric-sequences-in-mysql/)
The idea I want to share is not a precise response for the question but can be useful for some so I would like to share it.
If you frequently need only a limited set of numbers then it can be beneficial to create a table with the numbers you may need and just use that table every time. For example:
CREATE TABLE _numbers (num int);
INSERT _numbers VALUES (0), (1), (2), (3), ...;
This can be applied only if you need numbers below a certain reasonable limit, so don't use it for generating sequence 1...1 million but can be used for numbers 1...10k, for example.
If you have this list of numbers in the _numbers table then you can write queries like this, for obtaining the individual characters of a string:
SELECT number, substr(name, num, 1)
FROM users
JOIN _numbers ON num < length(name)
WHERE user_id = 1234
ORDER BY num;
If you need larger numbers than 10k then you can join the table to itself:
SELECT n1.num * 10000 + n2.num
FROM _numbers n1
JOIN _numbers n2
WHERE n1 < 100
ORDER BY n1.num * 10000 + n2.num; -- or just ORDER BY 1 meaning the first column
This is based on a previous answer (https://stackoverflow.com/a/53125278/2009581), but is compatible with MySQL 5.7. It works for replicas and read-only users:
SELECT x1.N + x10.N*10 + x100.N*100 + x1000.N*1000
FROM (SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) x1,
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) x10,
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) x100,
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) x1000
WHERE x1.N + x10.N*10 + x100.N*100 + x1000.N*1000 <= #max;
It generates integers in the range of [0, #max].
with recursive cte..
with recursive rnums as (
select 1 as n
union all
select n+1 as n from rnums
where n <10
)
select * from rnums
;
Result would be..
+------+
| n |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
+------+
10 rows in set (0.00 sec)