How to insert all the permutations of xxxxx number in MySQL? - mysql

I have a table called "numbers"
id (int, auto-increment)
number (varchar)
How can I insert all permutations of a number contating 5 digits [0-9] ?
00000
00001
00002
...
99999

Here is a select statement generating numbers from 0 to 99999 including 0 left padding. Then you can use this with INSERT statement to insert them where you want in a single shot.
SELECT LPAD(F.t*10000+E.num3,5,'0') num FROM
(
SELECT 100*num1+num2 num3
FROM (
SELECT t*10+u num1
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
) C,
(
SELECT t*10+u num2
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
) D
) E,
(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) F
ORDER BY num
Output is:
+-------+
| num |
+-------+
| 00000 |
| 00001 |
| 00002 |
| ... |
| 99999 |
+-------+

LPAD(str,len,padstr) - Returns the string str, left-padded with the string padstr to a length of len characters. If str is longer than len, the return value is shortened to len characters.
mysql> SELECT LPAD('hi',4,'??');
-> '??hi'
mysql> SELECT LPAD(123, 5,'0');
-> 00123
MySQL Documentation. 12.5 String Functions. function LPAD

Related

Retrieve multiple rows using DATE BETWEEN in MySQL

I have the below table structure.
ID | FromDate | ToDate
1 | 2020-01-02 | 2020-06-01
2 | 2020-08-01 | 2020-12-01
3 | 2020-01-02 | 2020-11-28
4 | 2020-04-01 | 2020-05-28
When I pass 2 input parameters named fromDate and toDate, it should select the relevant records.
E.g. If FromDate = 2020-01-01 and ToDate = 2020-06-01, it should return records with IDs 1 and 4 since those two records are between the dates as the parameters supplied.
I am using the below method at the moment and I feel like it's wasting a lot of resources.
AND ToDate IN (select * from
(select adddate('2000-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) selected_date 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) v
where selected_date between '2021-01-02 00:00:00' and '2022-03-02 00:00:00') ORDER BY name ASC,lt.ID ASC<code>
Is there any other way to achieve this task?
select * from table_name where fromDate>'2020-xx-xx' AND ToDate<'2020-xx-xx';
this query format can get records between insertion dates

how to group by a date range in MySQL and not skip dates with zero items

well, this might be easy but I can't seem to find any solution
I have this working query
SELECT
count(*), TIMESTAMPDIFF(DAY, buydate, NOW()) daydif
FROM
order_item
WHERE
buydate > NOW() - INTERVAL 4 DAY
GROUP BY daydif
ORDER BY daydif ASC
but the result is skipping the days with zero item
+----------+--------+
| count(*) | daydif |
+==========+========+
| 5 | 0 |
+----------+--------+
| 9 | 1 |
+----------+--------+
| 2 | 3 |
+----------+--------+
I want to get this result
+----------+--------+
| count(*) | daydif |
+==========+========+
| 5 | 0 |
+----------+--------+
| 9 | 1 |
+----------+--------+
| 0 | 2 | //I want this row in the returned results
+----------+--------+
| 2 | 3 |
+----------+--------+
Update:
From the answers and further search it seems I'm forced to create a helper table and join with it. It's so frustrating that I can't find a sequence producing function like that of MariaDB as mentioned in the comments. Any hint for a more elegant way?
Probably you do not have any items, where the difference is 2 days. SQL can't create something, that is not there.
What you can do is to have a table with a single field of long list of numbers from 0 to up to whatever the difference can be (in this case 4), let's call it tbl_diff, and the field is diff. Left join tbl_diff on your existing query to fill in the gaps. Note, that I also changed the count() to count those records only, where buydate is set.
SELECT
count(buydate), TIMESTAMPDIFF(DAY, buydate, NOW()) daydif
FROM
tbl_diff
LEFT JOIN
order_item on tbl_diff.diff=TIMESTAMPDIFF(DAY, buydate, NOW())
WHERE
diff<=4
GROUP BY daydif
ORDER BY daydif ASC
If you do not want to create a helper table, then you can operate with a series of unions because you only want 5 number (0 to 4):
SELECT
count(buydate), TIMESTAMPDIFF(DAY, buydate, NOW()) daydif
FROM
(SELECT 0 as diff FROM dual
UNION
SELECT 1 FROM dual
UNION
SELECT 2 FROM dual
UNION
SELECT 3 FROM dual
UNION
SELECT 4 FROM dual) tbl_diff
LEFT JOIN
order_item on tbl_diff.diff=TIMESTAMPDIFF(DAY, buydate, NOW())
GROUP BY daydif
ORDER BY daydif ASC
And as suggested by Paul Spiegel I ended up using some helper tables,
for future reference and better help here's the code to I used to generate the tables
create table `stat_helper_calendar` (
`date` DATE NOT NULL,
PRIMARY KEY (`date`)
)
select date_add('2015-01-01', INTERVAL t3.c*1000 + t2.c*100 + t1.c*10 + t0.c DAY) as `date`
from
(select 0 c 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) t0,
(select 0 c 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) t1,
(select 0 c 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) t2,
(select 0 c 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) t3
And this one for integers
CREATE TABLE `stat_helper_num` (
`num` INT NOT NULL,
PRIMARY KEY (`num`)
) SELECT (t4.c * 10000 + t3.c * 1000 + t2.c * 100 + t1.c * 10 + t0.c) AS `num` FROM
(SELECT 0 c 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) t0,
(SELECT 0 c 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) t1,
(SELECT 0 c 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) t2,
(SELECT 0 c 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) t3,
(SELECT 0 c 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) t4

Splitting letter in a string to separate row in MYSQL

I have days(working days for the school) field in school_calendar table as given below
select days from school_calendars where id=1;
returns MTWHF as result
I want the output as followed
+---------+
Days
+---------+
| M |
| T |
| W |
| H |
| F |
+---------+
Doing it for a string up to 1000 characters long:-
SELECT SUBSTR(days, aNum, 1) AS aDay
FROM school_calendars
INNER JOIN
(
SELECT 1 + units.aCnt + tens.aCnt * 10 + hundreds.aCnt * 100 AS aNum
FROM
(SELECT 0 AS aCnt 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) units.
(SELECT 0 AS aCnt 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) tens,
(SELECT 0 AS aCnt 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) hundreds
) sub0
ON sub0.aNum <= LENGTH(days)
WHERE id=1;
For a short varchar(7) that can be simplified to
SELECT SUBSTR(days, aNum, 1) AS aDay
FROM school_calendars
INNER JOIN
(
SELECT 1 AS aNum UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7
) sub0
ON sub0.aNum <= LENGTH(days)
WHERE id=1;

Mysql extend the phone number

In mysql database, I have those data as bellow:
id, phonenumber, location
1, 111222, NY
2, 222333, GB
....
Now I would extend the phonenumber field (varchar)
for example, if I extend one more number,
then the expect data would be:
id, phonenumber, location
1, 1112220, NY
2, 1112221, NY
3, 1112222, NY
4, 1112223, NY
5, 1112224, NY
6, 1112225, NY
7, 1112226, NY
8, 1112227, NY
9, 1112228, NY
10, 1112229, NY
11, 2223330, PH
12, 2223331, PH
...
And this is the example for add one more number.
The real situation is I would need to add 4 more number.
(add suffix from 0000 ~9999 )
Any fast way to do this via running few sql command ?
Thanks!
You can do this, although it is a bit of a pain in MySQL. You need to generate the values for extending The following does this:
select concat(n1.n, n2.n, n3.n, n4.n)
from (select 1 as n 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 union all select 0
) n1 cross join
(select 1 as n 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 union all select 0
) n2 cross join
(select 1 as n 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 union all select 0
) n3 cross join
(select 1 as n 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 union all select 0
) n4;
You can combine that with your query using cross join to get the data you want:
select id, concat(phonenumber, n1.n, n2.n, n3.n, n4.n) as phonenumber, location
from yourtable t cross join
(select 1 as n 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 union all select 0
) n1 cross join
(select 1 as n 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 union all select 0
) n2 cross join
(select 1 as n 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 union all select 0
) n3 cross join
(select 1 as n 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 union all select 0
) n4;
If you want these results in a table, I would suggest you save this to another table using:
create table as . . .
before the query.
Here is a SQL Fiddle.
You can use union query and cross join with your table which holds 2 phone numbers
select *, concat(phonenumber,n) new_phonenumber from t
cross join
( select 0 as n
union
select 1 as n
union
select 2 as n
union
select 3 as n
union
select 4 as n
union
select 5 as n
union
select 6 as n
union
select 7 as n
union
select 8 as n
union
select 9 as n
) t1
order by phonenumber, n
Sample demo
Please try this code
<?php
$con=mysql_connect("localhost","username","password");
$db=mysql_select_db("databasename");
$query="select * from table_name";
$result=mysql_query($query);
while($re=mysql_fetch_array($result))
{
echo $re[1];
}
?>
SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+
SELECT i4.i * 1000 + i3.i * 100 + i2.i*10 +i1.i j
FROM ints i1,ints i2, ints i3, ints i4
ORDER
BY j DESC
LIMIT 1;
+------+
| j |
+------+
| 9999 |
+------+

Generate list of dates and count online posts each day

I want to receive results like the sample output.
Listed each day beween two dates and the number of online posts from a company.
For example:
TABLE
id | online_From | online_To | comp_id
11 | 2014-04-02 | 2014-04-05 | 20
12 | 2014-04-11 | 2014-04-16 | 21
13 | 2014-04-03 | 2014-04-07 | 20
17 | 2014-04-29 | 2014-04-30 | 23
19 | 2014-04-04 | 2014-04-11 | 20
I want to receive:
SAMPLE OUTPUT
2014-04-01 | 0
2014-04-02 | 1
2014-04-03 | 2
2014-04-04 | 3
2014-04-05 | 3
2014-04-06 | 2
2014-04-07 | 2
2014-04-08 | 1
2014-04-09 | 1
2014-04-10 | 1
2014-04-11 | 1
2014-04-12 | 0
2014-04-13 | 0
…
2014-05-07 | 0
I used this mysql code to list the requested dates (and also split into y/m/d/w for generate charts):
select selected_date, year(selected_date) as y, day(selected_date) as d, week(selected_date) as w, month(selected_date) as m from
(select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i)
selected_date 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) v
where selected_date between '2014-04-01' and '2014-05-07'
GROUP BY y,m,d ORDER BY y ASC, m ASC, d ASC
2014-04-01|2014 |1 |14 |4 |0
2014-04-02|2014 |2 |14 |4 |1
2014-04-03|2014 |3 |14 |4 |2
…
This comes from: How to get list of dates between two dates in mysql select query
I tried a lot of things but I never became the hoped result.
I want to loop trough the dates and check the number of posts that where online that day.
Hopefully somebody can help me!
Thanks
This should get you started if you want a SQL-only answer. Have called your table comp_table...
select d.selected_date,d.d,d.m,d.y,
count(ct.id)
from
(
select selected_date, year(selected_date) as y, day(selected_date) as d, week(selected_date) as w, month(selected_date) as m from
(select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i)
selected_date 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) v
where selected_date between '2014-04-01' and '2014-05-07'
GROUP BY selected_date
) d
left outer join comp_table ct on d.selected_date between ct.online_From and ct.online_To
group by d.selected_date
order by 1 asc
;
You might be better off periodically populating an all_dates table to use in place of the inline view though. Would be more performant!
EDIT
If you want to maintain 'gimme all dates even if they have a 0 count' yet filter the results e.g. by the comp_id column then simply change the left outer join to include your filter by clause. For example:
select d.selected_date,d.d,d.m,d.y,
count(ct.id)
from
(
select selected_date, year(selected_date) as y, day(selected_date) as d, week(selected_date) as w, month(selected_date) as m from
(select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i)
selected_date 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) v
where selected_date between '2014-04-01' and '2014-05-07'
GROUP BY selected_date
) d
left outer join comp_table ct
on d.selected_date between ct.online_From and ct.online_To
and ct.comp_id = 20
group by d.selected_date
order by 1 asc
;
If you have not already installed it, I recommend you install common_schema. Once that's installed you can use the numbers table to simplify your query.
For example this query should give you the desired output:
select days.day,count(distinct your_table.id) from
(
select '2014-04-01' + interval n day AS day
from common_schema.numbers
having day between '2014-04-01' and '2014-05-07'
) days
left outer join your_table on your_table.online_From <= days.day and your_table.online_To >= days.day
group by days.day
order by days.day