How to add numbers into a table using SQL only on MySQL? - mysql

I want to add numbers from 100 to 9999 into a table using for loop. I have tried the following query:
DELIMITER //
BEGIN
FOR phone_number IN 100..9999 LOOP
INSERT INTO phones (`phoneid`,`phone`,`active`) VALUES (NULL, phone_number, "1");
END LOOP;
END
//
I have got the following error
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near'FOR phone_number IN 100..9999 LOOP INSERT INTO phones (`ph' at line 2
What is wrong?

i don't think in mysql exists "for loop". you can use this:
DELIMITER //
DROP PROCEDURE IF EXISTS ins//
CREATE PROCEDURE ins()
BEGIN
DECLARE cnt INT;
SET cnt=100;
WHILE cnt<10000 DO
INSERT INTO phones (`phoneid`,`phone`,`active`) VALUES (NULL, cnt, "1");
SET cnt=cnt+1;
END WHILE;
END//
DELIMITER ;
CALL ins();

You may generate desired values even without stored code, like:
INSERT INTO phones (
`phoneid`,
`phone`,
`active`
)
SELECT
NULL,
n0.n+10*n1.n+100*n2.n+1000*n3.n AS num,
"1"
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) AS n0
CROSS JOIN
(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) AS n1
CROSS JOIN
(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) AS n2
CROSS JOIN
(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) AS n3
HAVING
num>99
These CROSS JOIN will produce values 0..9999, so you'll have to filter those which are below 100 (that's why it has HAVING clause)

Related

Combining mySQL-Subqueries, dynamic BETWEENs?

I am working with MySQL and am trying to combine two Subqueries.
It is about time and excluding timespans.
The first (working) query fetches me every single valid day between two dates that are neigther saturday nor sunday (workdays):
SELECT * 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 '2021-04-01' and '2021-07-15'
AND weekday(selected_date) <> 5
AND weekday(selected_date) <> 6
The second query fetches me the start and end-Dates of vacations from a table (UNIX-Timestamps) and formats these dates the same way the first query returns them as 2 separate values (from, to):
SELECT date_format(FROM_UNIXTIME(from),'%Y-%m-%d') AS "from", date_format(FROM_UNIXTIME(to),'%Y-%m-%d') AS "to" FROM vacation
I am trying to eliminate every occurence of dates that are within these Timespans between 'from' and 'to' from my second query within my first query.
The thing that gets me is that i dont know how to set multiple BETWEENs dynamically to filter out those ranges. The second query returns multiple 'from' and 'to' values which i want to use as a "NOT BETWEEN-Filter" for my first query.
I hope what i said makes sense to you.
I am glad for every answer pushing me towards the right direction.
Thanks in advance
Felix
Use LEFT JOIN to join the two queries, and then a NULL check to exclude the matched rows.
SELECT t1.*
FROM (first query) AS t1
LEFT JOIN (second query) AS t2 ON t1.selected_date BETWEEN t2.from AND t2.to
WHERE t2.from IS NULL
It would also be better if the second query returned DATETIME values rather than formatted dates, so remove the calls to DATE_FORMAT().

SQL Subtraction one by one

I was thinking of subtracting digits one by one but didn't find a way to implement it after a big effort.
Row 1: 100211210
Row 2: 100010220
Result: 000201010
And the result has to be non-negative.
Select SUBSTR(t1.row,1,1)-(t2.row,1, 1)|| SUBSTR(t1.row,2,2)-SUBSTR(t2.row,2, 2)||... so on from table t1 where t1.row NOT IN (Select row in table t2);
This will check in the same table if the row exists then it will skip if not subtract digit by digit or you can use loop in pl/sql by declaring values for substr as i,j for both and then subtracting.
select GROUP_CONCAT(CAST(ABS(substring('123456782',c.count,1)-substring('323456789',c.count,1)) AS CHAR) separator '')
from (select c1.1*10+c2.1 count from (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 union all select 0) c1,
(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 union all select 0) c2 order by count) c
where c.count>0 and c.count<=length('123456782')
2 string is the same length, and the last parameter is the lenght of the strings

Mysql explode function

I have a table witch has a field with the following record:
1,2,3,4,5,6
I would like to ask the following two things:
1) How can i make a foreign key in another table? The rule would be:
For any value seperated by comma in field `field_name` must be record of other_table.field_id
2) How can i do something like: SELECT explode(field) AS ex FROM table_name ?
the name's of row maybe can retrieve as ex[0]-->1, ex[1]-->2
While it is possible to do a join on a comma separated field (using FIND_IN_SET for example), I don't think there is a way to do this for a foreign key.
MySQL doesn't have an explode function, and your idea would seem to suggest a varying number of columns on each row.
You can split them onto different rows if necessary but it is ugly. And more a good reason to NOT use comma separated fields
SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(field, ',', 1 + units.i + tens.i * 10 + hundreds.i * 100), ',', -1)
FROM table_name
CROSS JOIN (SELECT 0 AS 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) units
CROSS JOIN (SELECT 0 AS 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) tens
CROSS JOIN (SELECT 0 AS 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) hundreds

mysql return amount rows depending on field vlue

select id,name,total_copies from contacts.
that's the select statement. As is it can bring back
The result is
1,john,1
2,peter,3
3,sara,2
I need it to be
1,john,1
2,peter,2
2,peter,2
2,peter,2
3,sara,2
3,sara,2
So in a nutshell, if total_copies = 3 it must return the row 3 times, if value is 5 it must return row 5 times etc
You could use something like this:
SELECT contacts.*, n
FROM
(SELECT n1.n*10+n2.n n FROM
(SELECT 0 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) n1,
(SELECT 0 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) n2) numbers
INNER JOIN contacts ON contacts.total_copies>numbers.n
ORDER BY
id
Please see fiddle here. An indexed table with numbers should make the query easyer and faster:
CREATE TABLE numbers (n int);
INSERT INTO numbers VALUES (0), (1), (2), (3), (4), (5);
SELECT contacts.*
FROM numbers INNER JOIN contacts
ON contacts.total_copies>numbers.n
ORDER BY id;
Example here.

Dynamic SQL Procedure within function

I am trying to create a stored procedure that among other things, updates a table with information from other table:
UPDATE table1 T1, table2 T2
set T1.rank = T1.rank + T2.rank
T1.tags = merge(T1.tags, T2.tags)
WHERE T1.id = T2.id
tags is a string of comma separated words and merge is a function (not a procedure) that breaks the strings into temporary tables and returns the a new string with unique tags using prepared statements. I know can't use prepared statements inside functions but the part that uses those is inside a procedure that is called inside the function.
So I get an error starting that I can't use dynamic sql procedure inside a function
and I need the function so I can use the return value as the new value in the update.
Any Possible way to achive this?
You can do that (an update with merging tags) in one statement with pure SQL. The trick is in using a number aka tally table, which can be created and populated in seconds (also with one SQL statement).
Here is your UPDATE statement
UPDATE table1 t1 JOIN table2 t2
ON t1.id = t2.id JOIN
(
SELECT id, GROUP_CONCAT(DISTINCT tag ORDER BY tag) tags
FROM
(
SELECT a.id, SUBSTRING_INDEX(SUBSTRING_INDEX(tags, ',', n.id), ',', -1) tag
FROM
(
SELECT t1.id, CONCAT(t1.tags, ',', t2.tags) tags
FROM table1 t1 JOIN table2 t2
ON t1.id = t2.id
) a CROSS JOIN tally n
WHERE n.id <= 1 + (LENGTH(tags) - LENGTH(REPLACE(tags, ',', '')))
AND n.id < 100 -- change that number to accommodate max possible number of tags
) b
GROUP BY id
) c ON t1.id = c.id
SET t1.tags = c.tags,
t1.rank = t1.rank + t2.rank
Here is schema and statement that populates tally table with up to 100k rows.
CREATE TABLE tally (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
INSERT INTO tally
SELECT NULL
FROM (SELECT 0 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 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 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
, (SELECT 0 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) d
, (SELECT 0 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) e
;
Here is SQLFiddle demo