I need to insert some values in a table based on a condition. Basically I have 2 fields:
From and To
I need to insert the values in their range in increments of 11.
Suppose the following
From = 79090200
To = 79090233
So the following values would be saved:
79090200
79090211
79090222
79090233
I still a newbie so any help would mean a lot.
You can generate a range of numbers using UNION and insert based on that. Something like this:-
INSERT INTO SomeTable (SomeNumeric)
SELECT 79090200 + ((Units.i + Tens.i * 10 + Hundreds.i * 100) * 11) AS SomeNumber
(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) Units,
(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) Tens,
(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) Hundreds
HAVING SomeNumber BETWEEEN 79090200 AND 79090233
You can use below stored procedure to store these values in a table
DELIMITER $$
USE test$$
DROP PROCEDURE IF EXISTS `sp_increment`$$
CREATE DEFINER = `root`#`localhost` PROCEDURE `test`.`sp_increment`()
BEGIN
DECLARE start_val INT;
DECLARE end_val INT;
SET start_val=79090200;
SET end_val=79090233;
WHILE start_val <= end_val DO
INSERT INTO mytable (mycolumn) VALUES(start_val);
SET start_val = start_val + 11;
END WHILE;
END$$
DELIMITER ;
You can use below procedure to get values from a table-
DELIMITER $$
USE test$$
DROP PROCEDURE IF EXISTS `sp_increment`$$
CREATE DEFINER = `root`#`localhost` PROCEDURE `test`.`sp_increment`()
BEGIN
DECLARE s_val INT;
DECLARE e_val INT;
SELECT st_val, end_val INTO #start_val, #end_val FROM my_val;
SET s_val=#start_val;
SET e_val=#end_val;
WHILE s_val <= e_val DO
INSERT INTO increment_tbl VALUES(s_val);
SET s_val = s_val + 11;
END WHILE;
END$$
DELIMITER ;
Related
i have a table (Catalogs) on my Mariadb 10.1
id value
1 one ; two ; one
2 two ; three ; one
3 four ; five
4 one
5 four ; one
how do i count and group the value on Catalogs table like on the table below.
result count
one 5
two 2
three 1
four 2
five 1
or this table
id value
1 one
1 two
1 one
2 two
2 three
2 one
3 four
3 five
4 one
5 four
5 one
Taking reference from link http://www.marcogoncalves.com/2011/03/mysql-split-column-string-into-rows/
Assuming you have table named as table1 which contains two columns id and value and value column contains comma separated values.
Modified procedure:
CREATE PROCEDURE `explode_table`(bound VARCHAR(255))
BEGIN
DECLARE id INT DEFAULT 0;
DECLARE value TEXT;
DECLARE occurance INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
DECLARE splitted_value varchar(25);
DECLARE done INT DEFAULT 0;
DECLARE cur1 CURSOR FOR SELECT table1.id, table1.value
FROM table1
WHERE table1.value != '';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DROP TEMPORARY TABLE IF EXISTS table2;
CREATE TEMPORARY TABLE table2(
`id` INT NOT NULL,
`value` VARCHAR(56) NOT NULL
) engine=memory;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO id, value;
IF done THEN
LEAVE read_loop;
END IF;
SET occurance = (SELECT LENGTH(value)
- LENGTH(REPLACE(value, bound, ''))
+1);
SET i=1;
WHILE i <= occurance DO
SET splitted_value =
trim((SELECT REPLACE(SUBSTRING(SUBSTRING_INDEX(value, bound, i),
LENGTH(SUBSTRING_INDEX(value, bound, i - 1)) + 1), ';', '')));
INSERT INTO table2 VALUES (id, splitted_value);
SET i = i + 1;
END WHILE;
END LOOP;
CLOSE cur1;
SELECT * FROM table2;
END
A plain SQL way of doing it, which will cope with up to 100 split delimited values (easily expanded to cope with more if necessary):-
SELECT result, COUNT(id)
FROM
(
SELECT id, SUBSTRING_INDEX(SUBSTRING_INDEX(value, ' ; ', tens.anum * 10 + units.anum + 1), ' ; ', -1) AS result
FROM Catalogs
CROSS JOIN
(SELECT 1 AS anum 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 anum 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
WHERE LENGTH(value) - LENGTH(REPLACE(value, ';', '')) >= ( tens.anum * 10 + units.anum)
) sub0
GROUP BY result
I've created a stored procedure to populate all dates in a given month &year into a table 'month_date' (date column)
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$
CREATE DEFINER="root"#"localhost" PROCEDURE "populate_date"(IN p_month varchar(3),
IN p_year varchar(4))
MODIFIES SQL DATA
DETERMINISTIC
BEGIN
declare l_month varchar(9);
set l_month = '01'+p_month+p_year;
insert into month_date
SELECT date_field
FROM
(
SELECT
STR_TO_DATE(l_month, '%d%b%Y')+
INTERVAL daynum DAY date_field
FROM
(
SELECT t*10+u daynum
FROM
(SELECT 0 t UNION SELECT 1 UNION SELECT 2 UNION SELECT 3) 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
ORDER BY daynum
) AA
) AAA
WHERE MONTH(date_field) = MONTH(STR_TO_DATE(l_month, '%d%b%Y'));
commit;
END
when I am calling this procedure
call sms.populate_date('Sep','2015');
its throwing error
Incorrect datetime value: '2016' for function str_to_date
I've run the sql on its own and its working fine.
SELECT date_field
FROM
(
SELECT
STR_TO_DATE('01Sep2015', '%d%b%Y')+
INTERVAL daynum DAY date_field
FROM
(
SELECT t*10+u daynum
FROM
(SELECT 0 t UNION SELECT 1 UNION SELECT 2 UNION SELECT 3) 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
ORDER BY daynum
) AA
) AAA
WHERE MONTH(date_field) = MONTH(STR_TO_DATE('01Sep2015', '%d%b%Y'));
please can you help with this error?
thanks
You need to combine your Strings with the CONCAT()-Function. The + is just for an addition:
....
BEGIN
declare l_month varchar(9);
/*ADDED CONCAT HERE*/
set l_month = CONCAT('01',p_month,p_year);
insert into month_date
SELECT date_field
FROM
(
....
Problem:
I want to test a set of values is equal to another set but not necessary their order of position will be same.
For example:
'a,b,c,d' must be equal to 'b,a,c,d'
What I have tried:
I have tried IN Clause and I have checked with FIND_IN_SET.
SELECT 'a,b,c,d' IN 'b,c,a,d';
Both of them can not do this work.
Will be thankful if anyone can help.
Thanks
Sandeep
This demonstrates the use the splitting of values to multiple rows, mentioned by GolezTrol in combination with FIND_IN_SET, modified to function to be used in forms like:
SELECT are_sets_equal(col_with_set, 'a,b,d,c') FROM example;
or
SELECT * FROM example
WHERE are_sets_equal(col_with_set, 'a,b,d,c')
The idea is this:
Split the the first set to a temporary table
Check how many of those values are found in the second set.
If this count is equal to the count of elements in both sets, then the sets are equal
The function will return 1, if both sets are equal and 0, if the sets differ as by requirement.
The limit for both sets is 1000 values, but could be expanded easily:
DELIMITER //
CREATE FUNCTION are_sets_equal(set_a VARCHAR(2000), set_b VARCHAR(2000)) RETURNS BOOLEAN
BEGIN
DECLARE is_equal BOOLEAN;
DECLARE count_a INT;
DECLARE count_b INT;
-- calculate the count of elements in both sets
SET count_a = 1 + LENGTH(set_a) - LENGTH(REPLACE(set_a, ',', ''));
SET count_b = 1 + LENGTH(set_b) - LENGTH(REPLACE(set_b, ',', ''));
SELECT
-- if all elements of the first set are contained in the second
-- set and both sets have the same number of elements then both
-- sets are considered equal
COUNT(t.value) = count_a AND count_a = count_b INTO is_equal
FROM (
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(e.col, ',', n.n), ',', -1) value
FROM ( SELECT set_a AS col ) e
CROSS JOIN(
-- build for up to 1000 separated values
SELECT
a.N + b.N * 10 + c.N * 100 + 1 AS 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
ORDER BY n
) n
WHERE n.n <= count_a
) t
WHERE FIND_IN_SET(t.value, set_b);
return is_equal;
END //
DELIMITER ;
Explanation
Building a numbers table
SELECT
a.N + b.N * 10 + c.N * 100 + 1 AS 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
ORDER BY n
builds a number table with the values from 1 to 1000 on the fly. How to expand this to a greater range should be obvious.
Note Such a numbers table could be contained in your database, so there would be no need to create one on the fly.
Split a set to a table
With the help of this number table we can split the value list to a table, using nested SUBSTRING_INDEX calls to cut just one value after the other from the list as mentioned in SQL split values to multiple rows:
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(t.col, ',', n.n), ',', -1) value
FROM (SELECT #set_a as col ) t CROSS JOIN (
-- build for up to 100 separated values
SELECT
a.N + b.N * 10 + c.N * 100 + 1 AS 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
ORDER BY n
) n
WHERE
n <= 1 + LENGTH(#set_a) - LENGTH(REPLACE(#set_a, ',', ''))
Count the elements of the sets
We get the count of elements in the list by the expression in the WHERE clause: we have one more values than occurences of the separator.
Then we restrict the result by searching those values in the second set with FIND_IN_SET.
As a last step we check count of values in the result against the count of values in both sets and return this value.
Demo
Experiment with this demo.
FIND_IN_SET should do the trick, but the first value is an individual value and doesn't work right if it contains a comma. You would have to look for each individual value:
SELECT
FIND_IN_SET('a', 'b,c,a,d') AND
FIND_IN_SET('b', 'b,c,a,d') AND
FIND_IN_SET('c', 'b,c,a,d') AND
FIND_IN_SET('d', 'b,c,a,d')
If you don't have these separate values available, maybe you can split the input value into multiple values. The answers to the question 'Split values to multiple rows' might give you some inspiration.
The better solution would be not to store comma separated values at all. It's considered bad practice.
You can use a UDF(user defined function) to compare your sets,As from comments no duplicate values will be in the sets,I have little customized a UDF function provided by #Simon at mso.net.I have calculated a count of values in a second comma separated list and in the end compared with the matched result of find_in_set stored in numReturn variable,If both equal the return 1 else return 0 for non matched.Please not this will not work for repeated/duplicate values in a set
DELIMITER $$
DROP FUNCTION IF EXISTS `countMatchingElements`$$
CREATE DEFINER = `root` #`localhost` FUNCTION `countMatchingElements` (
inFirstList VARCHAR (1000),
inSecondList VARCHAR (1000)
) RETURNS TINYINT (3) UNSIGNED NO SQL DETERMINISTIC SQL SECURITY INVOKER
BEGIN
DECLARE numReturn TINYINT UNSIGNED DEFAULT 0 ;
DECLARE idsInFirstList TINYINT UNSIGNED ;
DECLARE currentListItem VARCHAR (255) DEFAULT '' ;
DECLARE currentID TINYINT UNSIGNED ;
DECLARE total_values_in_second INT DEFAULT 0 ;
SET total_values_in_second = ROUND(
(
LENGTH(inSecondList) - LENGTH(REPLACE (inSecondList, ',', ''))
) / LENGTH(',')
) + 1 ;
SET idsInFirstList = (CHAR_LENGTH(inFirstList) + 1) - CHAR_LENGTH(REPLACE(inFirstList, ',', '')) ;
SET currentID = 1 ;
-- Loop over inFirstList, and for each element that is in inSecondList increment numReturn
firstListLoop :
REPEAT
SET currentListItem = SUBSTRING_INDEX(
SUBSTRING_INDEX(inFirstList, ',', currentID),
',',
- 1
) ;
IF FIND_IN_SET(currentListItem, inSecondList)
THEN SET numReturn = numReturn + 1 ;
END IF ;
SET currentID = currentID + 1 ;
UNTIL currentID > idsInFirstList
END REPEAT firstListLoop ;
IF total_values_in_second = numReturn
THEN RETURN 1 ;
ELSE RETURN 0 ;
END IF ;
END $$
DELIMITER ;
Fiddle Demo
MySQL stored procedures can be used to split the string, the following details for your usage of MySQL stored procedures, for your reference learning purposes.
Existing string, such as Apple, banana, orange, pears, grape, it should follow the comma (,) is divided into:
apple
banana
orange
pears
grape
Where in () method can then query.
1, the specific function:
Function: func_split_TotalLength the
DELIMITER $ $
DROP function IF EXISTS `func_split_TotalLength` $ $
CREATE DEFINER = `root` # `%` FUNCTION `func_split_TotalLength`
(F_string varchar (1000), f_delimiter varchar (5)) RETURNS int (11)
BEGIN
return 1 + (length (f_string) - length (replace (f_string, f_delimiter,'')));
END $ $
DELIMITER;
Function: func_split
DELIMITER $ $
DROP function IF EXISTS `func_split` $ $
CREATE DEFINER = `root` # `%` FUNCTION `func_split`
(F_string varchar (1000), f_delimiter varchar (5), f_order int) RETURNS varchar (255) CHARSET utf8
BEGIN
declare result varchar (255) default '';
set result = reverse (substring_index (reverse (substring_index (f_string, f_delimiter, f_order)), f_delimiter, 1));
return result;
END $ $
DELIMITER;
Stored procedure: SplitString
DELIMITER $ $
DROP PROCEDURE IF EXISTS `splitString` $ $
CREATE Procedure the `SplitString`
(IN f_string varchar (1000), IN f_delimiter varchar (5))
BEGIN
declare cnt int default 0;
declare i int default 0;
set cnt = func_split_TotalLength (f_string, f_delimiter);
DROP TABLE IF EXISTS `tmp_split`;
create temporary table `tmp_split` (`status` varchar (128) not null) DEFAULT CHARSET = utf8;
while i <cnt
do
set i = i + 1;
insert into tmp_split (`status`) values ??(func_split (f_string, f_delimiter, i));
end while;
END $ $
DELIMITER;
2, the test will be successful segmentation
call splitString ("apple, banana, orange, pears, grape", ",");
select * from tmp_split;
The results are splitting success:
mysql> call splitString ("apple, banana, orange, pears, grape", ",");
select * from tmp_split;
Query OK, 1 row affected but i need to insert by column wise data...,please help me
Well I would use an other approach to this problem, to get the result in table form:
Simpler approach without a stored procedure
Assuming you have a table example with two columns: id and col1 like so:
CREATE TABLE example (
id INT NOT NULL PRIMARY KEY,
col1 VARCHAR(1000)
);
and those values
id | col
-----------------------------
1 | abcd,efgh,ijkl,ghjy,sdfg
2 | some other text
and you want to get the comma separated values from col into a column with one value at the time for the id = 1. Then I would use following sql:
SELECT
id,
SUBSTRING_INDEX(SUBSTRING_INDEX(e.col, ',', t.n), ',', -1) value
FROM example e CROSS JOIN (
SELECT
1 + a.N + b.N * 10 + c.N * 100 AS 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
ORDER BY n
) t
WHERE
e.id = 1
AND
t.n <= (1 + LENGTH(e.col) - LENGTH(REPLACE(e.col, ',', '')));
It's the same procedure as in the stored procedure. You can use this result easily in joins or other operations.
See this Demo
First part assuming, a stored procedure was needed.
stored procedure
no other function needed
no explicit temp table
works up to 1000 items, easily exptensible
Code:
DROP procedure splitString;
DELIMITER $ $
CREATE procedure splitString(IN f_string VARCHAR(1000), IN f_delimiter VARCHAR(5))
BEGIN
SELECT SUBSTRING_INDEX(
SUBSTRING_INDEX(h.haystack, f_delimiter, t.n
), f_delimiter, -1) as value
FROM (SELECT f_string as haystack) h
CROSS JOIN (
SELECT
1 + a.N + b.N * 10 + c.N * 100 AS 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
ORDER BY n
) t
WHERE t.n <=
(
1
+ (
CHAR_LENGTH(f_string)
-
CHAR_LENGTH(REPLACE(f_string, f_delimiter, ''))
)
/ CHAR_LENGTH(f_delimiter)
);
END;
$ $
DELIMITER ;
Explanation
1. Generating a list of numbers from 1 to 1000
The most inner SELECT
SELECT
1 + a.N + b.N * 10 + c.N * 100 AS 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
ORDER BY n
does not more than creating a list with the numbers from 1 to 1000. If you need more then you should see, how it's done. Add a line with those union all and call this d, add + d.N * 1000 to the sum.
2. Performing the split and getting just one element per row
We use this list to do the split of your func_split in the form of (a bit more readable statements)
SELECT SUBSTRING_INDEX(
SUBSTRING_INDEX(h.haystack, f_delimiter, 1
), f_delimiter, -1) as value
FROM (SELECT f_string as haystack) h
SELECT SUBSTRING_INDEX(
SUBSTRING_INDEX(h.haystack, f_delimiter, 2
), f_delimiter, -1) as value
FROM (SELECT f_string as haystack) h
SELECT SUBSTRING_INDEX(
SUBSTRING_INDEX(h.haystack, f_delimiter, 3
), f_delimiter, -1) as value
FROM (SELECT f_string as haystack) h
that extract the first, second, third, ... substring, separated with the f_delimiter.
Getting the number of elements
Our WHERE clause is all but self-explanatory:
-- because we begin by 1 we've got to include the upper limit
WHERE t.n <=
(
1 -- we have one comma less than parts
+ (
-- count how many characters (not bytes) we lose by the replace operation
CHAR_LENGTH(f_string)
-
CHAR_LENGTH(REPLACE(f_string, f_delimiter, ''))
)
-- and divide this by the count of characters in the delimiter string
/ CHAR_LENGTH(f_delimiter)
);
Note
LENGTH() instead of CHAR_LENGTH() would do too, because the result of the division would be the same, but I like to do it right :-)
** Check of function**
You can check the result with
CALL splitString('apple, bananas, grape, ananas, pears', ', ');
it returns
value
-----
apple
bananas
grape
ananas
pears
I need to write a script that creates and calls a stored procedure named test. This procedure should calculate the common factors between 10 and 20. To find a common factor, you can use the modulo operator (%) to check whether a number can be evenly divided into both numbers. Then, this procedure should display a string that displays the common factors like this:
Common factors of 10 and 20: 1 2 5 Thanks in advance!
Here is what I have so far:
`USE my_guitar_shop;
DROP PROCEDURE IF EXISTS test;
-- Change statement delimiter from semicolon to double front slash
DELIMITER //
CREATE PROCEDURE test()
BEGIN
DECLARE counts INT Default 1;
DECLARE factor10;
DECLARE factor20;
DECLARE FACTORS varchar(100);
simple_loop: LOOP
SELECT 10
MOD counts
into factor10;
SELECT 20
MOD counts
into factor20;
WHEN (factor10 = 0 && factor20 = 0) THEN
SELECT concat("Common factors of 10 and 20:";
WHEN
END//
-- Change statement delimiter from semicolon to double front slash
DELIMITER ;
CALL test(); `
How about a version without loops?
CREATE PROCEDURE test(IN _first INT, _second INT)
SELECT CONCAT('Common factors of ', LEAST(_first, _second), ' and ', GREATEST(_first, _second), ': ', GROUP_CONCAT(n)) result
FROM
(
SELECT n
FROM
(
SELECT a.N + b.N * 10 + c.N * 100 + 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
ORDER BY n
) n
WHERE n <= LEAST(_first, _second)
HAVING _first MOD n = 0
AND _second MOD n = 0
) q;
Usage:
mysql> CALL test(10, 20);
+---------------------------------------+
| result |
+---------------------------------------+
| Common factors of 10 and 20: 1,2,5,10 |
+---------------------------------------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
mysql> CALL test(800, 1000);
+------------------------------------------------------------------+
| result |
+------------------------------------------------------------------+
| Common factors of 800 and 1000: 1,2,4,5,8,10,20,25,40,50,100,200 |
+------------------------------------------------------------------+
1 row in set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
Here is SQLFiddle demo
USE my_guitar_shop;
DROP PROCEDURE IF EXISTS test;
DELIMITER //
CREATE PROCEDURE test()
BEGIN
DECLARE factor10 INT;
DECLARE factor20 INT;
DECLARE counter INT;
DECLARE result VARCHAR(50);
SET factor10 = 10;
SET factor20 = 20;
SET counter = 1;
SET result = 'Common factors of 10 and 20: ';
WHILE (counter <= factor10/2) DO
IF (factor10 % counter = 0 AND factor20 % counter = 0) THEN
SET result = CONCAT(result, counter, ' ');
END IF;
SET counter = counter+1;
END WHILE;
/* IF (factor10 % factor10 = 0 AND factor20 % factor10 = 0) THEN
SET result = CONCAT(result, factor10, ' ');
END IF;
*/
SELECT result AS message;
END //
DELIMITER ;
CALL test();