MySQL) How to remove duplicated rows working with WHILE loop? - mysql

I have a table called cart and an empty table sort in database. My goal is to transmit & split values in comma spread from one table to another like this:
(table cart)
id | food
---+--------------
1 | Carrots, Cucumbers
2 | Dandelions
3 | Salmons
4 | Cucumbers, Potatoes
5 | Tomatoes
(table sort after run query)
id | food
---+--------------
1 | Carrots
1 | Cucumbers
2 | Dandelions
3 | Salmons
4 | Cucumbers
4 | Potatoes
5 | Tomatoes
An issue is, it seems like the keywords DISTINCT, GROUP BY and ORDER BY won't work properly inside of the WHILE clause. When I run my query, MySQL inserts a whole list of values multiple times based on a total of id count.
Have a look at this query:
DELIMITER //
CREATE FUNCTION fx_splitString(columnName TEXT, pos INT)
RETURNS TEXT
RETURN TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(columnName, ',', pos), ',', -1)) //
CREATE PROCEDURE pd_splitRow()
BEGIN
DECLARE rowToll INT;
SET rowToll = (SELECT COUNT(id) FROM cart);
SET #outerCount = 1;
WHILE #outerCount <= rowToll DO
INSERT INTO sort (id, food)
SELECT DISTINCT id, fx_splitString(food, #stringToll) FROM cart;
SET #outerCount = #outerCount + 1;
END WHILE;
END //
DELIMITER ;
CALL pd_splitRow();
Now I'm trying to find other ways to accomplish this but none of these work.
Try 1: Nested Loop
This idea is aborted because MySQL won't allow to set multiple rows. I can't use to create variable
Error Code: 1242. Subquery returns more than 1 row 0.016 sec
DECLARE rowToll INT;
SET rowToll = (SELECT COUNT(id) FROM cart);
SET #stringToll = (SELECT LENGTH(food) - LENGTH(REPLACE(food, ',', '')) + 1 FROM cart); /* error */
SET #outerCount = 1;
SET #innerCount = 1;
WHILE #outerCount <= rowToll DO
WHILE #innerCount <= #stringToll DO
INSERT INTO sort (id, food)
SELECT DISTINCT id, fx_splitString(food, #stringToll) FROM cart;
SET #innerCount = #innerCount + 1;
END WHILE;
SET #outerCount = #outerCount + 1;
END WHILE;
Try 2: Self Join
This one simply does not insert any of values from cart table.
WHILE #begin <= rowCount DO
INSERT INTO sort (id, food)
SELECT DISTINCT cte1.id, fx_splitString(cte1.food, #begin) FROM cart cte1
INNER JOIN cart cte2 ON cte1.id = cte2.id AND cte1.food = cte2.food;
SET #begin = #begin + 1;
END WHILE;
I could just use in the examples from the other guys' query but I want to create my own for improving skills.
Are there any ways to group the rows working with WHILE loop?

Related

MySQL - copy or update rows with a change within one table

I have a database table like this one:
group | detailsID | price
EK | 1 | 1.40
EK | 2 | 1.50
EK | 3 | 1.60
H | 1 | 2.40
H | 2 | 2.50
Now I want to copy the data from group "EK" to the group "H", so the prices for the detailsID's must be adjusted for the detailsIDs 1 and 2, and the entry for detailsID 3 must be inserted for group "H".
How can I do that with one or two MySQL query's?
Thanks!
We can try doing an INSERT INTO ... SELECT with ON DUPLICATE KEY UPDATE:
INSERT INTO yourTable (`group`, detailsID, price)
SELECT 'H', detailsID, price
FROM yourTable t
WHERE `group` = 'EK'
ON DUPLICATE KEY UPDATE price = t.price;
But this assumes that there exists a unique key on (group, detailsID). If this would not be possible, then this approach would not work.
As an alternative, I might do this in two steps. First, remove the H group records, then insert the updated H records you expect.
DELETE
FROM yourTable
WHERE `group` = 'H';
INSERT INTO yourTable (`group`, detailsID, price)
SELECT 'H', detailsID, price
FROM yourTable
WHERE `group` = 'EK';
I use the above approach because a single update can't handle your requirement, since new records also need to be inserted.
Note that you should avoid naming your columns and tables using reserved MySQL keywords such as GROUP.
You can try this as well, Following code implemented using stored procedures. Very simple not that difficult to understand. You may need to modify data type and optimize the code as per the requirement.
DELIMITER $$;
DROP PROCEDURE IF EXISTS update_H $$;
CREATE PROCEDURE update_H()
BEGIN
DECLARE finished INTEGER DEFAULT 0;
DECLARE `group_col` varchar(255) DEFAULT "";
DECLARE `detaildid_col` varchar(255) DEFAULT "";
DECLARE `price_col` varchar(255) DEFAULT "";
DECLARE H_FOUND INTEGER DEFAULT 0;
DECLARE pull_data CURSOR FOR select `group`, `detaildid`, `price` from test.newtab WHERE `group` = 'EK';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
OPEN pull_data;
traverse_data: LOOP
FETCH pull_data INTO group_col, detaildid_col, price_col;
IF finished = 1 THEN
LEAVE traverse_data;
END IF;
SET H_FOUND = (SELECT count(*) from test.newtab where `group` = 'H' AND `detaildid` = detaildid_col);
IF ( H_FOUND = 1 ) THEN
UPDATE test.newtab SET `price` = price_col where `group` = 'H' AND `detaildid` = detaildid_col;
ELSE
INSERT INTO test.newtab (`group`, `detaildid`, `price`) VALUES ('H', detaildid_col, price_col);
END IF;
END LOOP traverse_data;
CLOSE pull_data;
END $$;
DELIMITER ;
You can call this procedure by executing, call update_H();

Batch MYSQL inserts for performance in DB structure migration

I need to restructure my MYSQL InnoDB database.
At the moment I have a customer table holding 3 product names.
I need to extract these names to a new product table. The product table should hold each name currently held in the customer table and be linked to the customer table via a new customer_product table. While the product names may not be unique, they don't have anything to do with each other, meaning for each customer there will need to be inserted 3 new entries into the product table and 3 new entries into the customer_product table.
So instead of this:
customer
| id | product_name_a | product_name_b | product_name_c |
I need this:
customer
| id |
customer_product
| customer_id | product_id | X3
product
| id | name | X3
I've written the following MYSQL procedure that works:
BEGIN
DECLARE nbr_of_customers BIGINT(20);
DECLARE customer_count BIGINT(20);
DECLARE product_id BIGINT(20);
DECLARE customer_id BIGINT(20);
DECLARE product_name_a VARCHAR(500);
DECLARE product_name_b VARCHAR(500);
DECLARE product_name_c VARCHAR(500);
SELECT COUNT(*) FROM customer INTO nbr_of_customers;
SET customer_count = 0;
SET product_id = 1;
WHILE customer_count < nbr_of_customers DO
SELECT
customer.id,
customer.product_name_a,
customer.product_name_b,
customer.product_name_c
INTO
customer_id,
product_name_a,
product_name_b,
product_name_c
FROM customer
LIMIT customer_count,1;
INSERT INTO product(id, name)
VALUES(product_id, product_name_a);
INSERT INTO customer_product(customer_id, product_id)
VALUES(customer_id, product_id);
SET product_id = product_id + 1;
INSERT INTO product(id, name)
VALUES(product_id, product_name_b);
INSERT INTO customer_product(customer_id, product_id)
VALUES(customer_id, product_id);
SET product_id = product_id + 1;
INSERT INTO product(id, name)
VALUES(product_id, product_name_c);
INSERT INTO customer_product(customer_id, product_id)
VALUES(customer_id, product_id);
SET product_id = product_id + 1;
SET customer_count = customer_count + 1;
END WHILE;
END;
This is too slow.
I've run this locally and estimate that my ~15k customers would take ~1h to complete. And my VPS server is far slower than that, so it could take upward to 10h to complete.
The problem seem to be the inserts taking a long time. I've would therefore like to store all the inserts during the procedure and execute them all in batch after the loop is complete and I know what to insert.
I there a way to perform all the ~100k inserts in batch to optimize performance, or is there a better way to do it?
FINAL EDIT:
I marked the correct solution based on that it did an excellent job of speeding up the process massively, which was the main focus of the question. In the end I ended up performing the migration using modified production code (in Java), due to the solution's limitations regarding not escaping the inserted strings.
First, use a cursor to process the results of a single query, rather than performing a separate query for each row.
Then concatenate the VALUES lists into strings that you execute using PREPARE and EXECUTE.
My code does the inserts in batches of 100 customers, because I expect there's a limit on the size of a query.
BEGIN
DECLARE product_id BIGINT(20);
DECLARE customer_id BIGINT(20);
DECLARE product_name_a VARCHAR(500);
DECLARE product_name_b VARCHAR(500);
DECLARE product_name_c VARCHAR(500);
DECLARE done INT DEFAULT FALSE;
DECLARE cur CURSOR FOR SELECT c.id, c.product_name_a, c.product_name_b, c.product_name_c FROM customer AS c;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
SET product_id = 1;
OPEN cur;
SET #product_values = '';
SET #cp_values = '';
read_loop: LOOP
FETCH cur INTO customer_id, product_name_a, product_name_b, product_name_c;
IF done THEN
LEAVE read_loop;
END IF;
SET #product_values = CONCAT(#product_values, IF(#product_values != '', ',', ''), "(", product_id, ",'", product_name_a, "'), (", product_id + 1, ",'", product_name_b, "'), (", product_id + 2, ",'", product_name_c, "'), ");
SET #cp_values = CONCAT(#cp_values, IF(#cp_values != '', ',', ''), "(", customer_id, ",", product_id, "), (", customer_id, ",", product_id + 1, "), (", customer_id, ",", product_id + 2, "),");
SET product_id = product_id + 3;
IF product_id % 300 = 1 -- insert every 100 customers
THEN BEGIN
SET #insert_product = CONCAT("INSERT INTO product(id, name) VALUES ", #product_values);
PREPARE stmt1 FROM #insert_product;
EXECUTE stmt1;
SET #insert_cp = CONCAT("INSERT INTO customer_product(customer_id, product_id) VALUES ", #cp_values);
PREPARE stmt2 FROM #insert_cp;
EXECUTE stmt2;
SET #product_values = '';
SET #cp_values = '';
END IF;
END LOOP;
IF #product_values != '' -- Process any remaining rows
THEN BEGIN
SET #insert_product = CONCAT("INSERT INTO product(id, name) VALUES ", #product_values);
PREPARE stmt1 FROM #insert_product;
EXECUTE stmt1;
SET #insert_cp = CONCAT("INSERT INTO customer_product(customer_id, product_id) VALUES ", #cp_values);
PREPARE stmt2 FROM #insert_cp;
EXECUTE stmt2;
SET #product_values = '';
SET #cp_values = '';
END IF;
END;
Beware that, using this solution, the product names will not be properly escaped before inserting. This solution will therefore not work if any of the product names contains special characters, such as single quote '.
Perhaps you could do this in three separate inserts (instead of ~100K) as follows:
INSERT INTO customer_product (customer_id, product_id)
SELECT customer.id as customer_id, product.id as product_id
FROM customer
JOIN product on customer.product_name_a = product.name
INSERT INTO customer_product (customer_id, product_id)
SELECT customer.id as customer_id, product.id as product_id
FROM customer
JOIN product on customer.product_name_b = product.name
INSERT INTO customer_product (customer_id, product_id)
SELECT customer.id as customer_id, product.id as product_id
FROM customer
JOIN product on customer.product_name_c = product.name
Of course, you would have to set up your product table ahead of time, and you'd want to drop your de-normalized columns from your customer table after the fact.
This could be further sped up if you create an index on the customer.product_name_X columns (and possibly the product.name column, though it's so few, idk if it would be significant). EXPLAIN can help with that.

Selecting values with more than one occurrence of a character in SQL

Let me explain my question with an example
Consider the following column of values
City
-------
Chennai
Delhi
Mumbai
Output I want is
City
-------
Chennai
Mumbai
When you look at the values 'Chennai' has two 'N's and 'Mumbai' has two 'M's
What is the query to find the values that satisfy the above said condition
I am using MySQL
You may be able to use some of the logic from here and then filter that way Count all occurances of different characters in a column
Can u try this. If you want you can create function and accepts dynamic value and pass to the corresponding function
IF(LEN('Chennai')-LEN(REPLACE('Chennai', 'N', ''))>1 )
Select 'Chennai'
A possible solution if city names contain only latin characters
SELECT DISTINCT city
FROM table1 c CROSS JOIN
(
SELECT 0 n UNION ALL
SELECT a.N + b.N * 5 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) b
ORDER BY n
) n
WHERE CHAR_LENGTH(city) - CHAR_LENGTH(REPLACE(LOWER(city), CHAR(97 + n.n), '')) > 1
Output:
| CITY |
|---------|
| Mumbai |
| Chennai |
Here is SQLFiddle demo
You can use stored procedure for this. Please check my code -
Create table statement -
CREATE TABLE `Cities` (
`City` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Added cities to table and created procedure -
CREATE PROCEDURE `SP_SplitString`()
BEGIN
DECLARE front TEXT DEFAULT NULL;
DECLARE count INT DEFAULT 0;
DECLARE arrayText longtext default "";
DECLARE Value longtext DEFAULT "";
DECLARE val longtext DEFAULT "";
DECLARE done INT DEFAULT FALSE;
DECLARE cityCursor CURSOR FOR SELECT * FROM `Cities`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cityCursor;
loop_through_rows:
LOOP
FETCH cityCursor INTO Value;
IF done THEN
LEAVE loop_through_rows;
END IF;
SET val = Value;
iterator:
LOOP
IF LENGTH(TRIM(val)) = 0 OR val IS NULL THEN
LEAVE iterator;
END IF;
SET front = LOWER(SUBSTRING(val,1,1));
SET count = LENGTH(Value) - LENGTH(REPLACE(LOWER(Value), front, ''));
IF count > 1 THEN
IF LENGTH(TRIM(arrayText)) = 0 THEN
SET arrayText = Value;
ELSE
SET arrayText = CONCAT(arrayText,",",Value);
END IF;
LEAVE iterator;
END IF;
IF LENGTH(TRIM(val)) > 1 THEN
SET val = SUBSTRING(val,2,LENGTH(TRIM(val)));
ELSE
SET val = "";
END IF;
END LOOP;
END LOOP;
SELECT * FROM `Cities` WHERE FIND_IN_SET(City, arrayText);
END

MySql Recursive Query Alternative? [duplicate]

I have the following table:
id | parent_id | quantity
-------------------------
1 | null | 5
2 | null | 3
3 | 2 | 10
4 | 2 | 15
5 | 3 | 2
6 | 5 | 4
7 | 1 | 9
Now I need a stored procedure in mysql that calls itself recursively and returns the computed quantity.
For example the id 6 has 5 as a parent which as 3 as a parent which has 2 as a parent.
So I need to compute 4 * 2 * 10 * 3 ( = 240) as a result.
I am fairly new to stored procedures and I won't use them very often in the future because I prefer having my business logic in my program code rather then in the database. But in this case I can't avoid it.
Maybe a mysql guru (that's you) can hack together a working statement in a couple of seconds.
its work only in mysql version >= 5
the stored procedure declaration is this,
you can give it little improve , but this working :
DELIMITER $$
CREATE PROCEDURE calctotal(
IN number INT,
OUT total INT
)
BEGIN
DECLARE parent_ID INT DEFAULT NULL ;
DECLARE tmptotal INT DEFAULT 0;
DECLARE tmptotal2 INT DEFAULT 0;
SELECT parentid FROM test WHERE id = number INTO parent_ID;
SELECT quantity FROM test WHERE id = number INTO tmptotal;
IF parent_ID IS NULL
THEN
SET total = tmptotal;
ELSE
CALL calctotal(parent_ID, tmptotal2);
SET total = tmptotal2 * tmptotal;
END IF;
END$$
DELIMITER ;
the calling is like
(its important to set this variable) :
SET ##GLOBAL.max_sp_recursion_depth = 255;
SET ##session.max_sp_recursion_depth = 255;
CALL calctotal(6, #total);
SELECT #total;
Take a look at Managing Hierarchical Data in MySQL by Mike Hillyer.
It contains fully worked examples on dealing with hierarchical data.
How about avoiding procedures:
SELECT quantity from (
SELECT #rq:=parent_id as id, #val:=#val*quantity as quantity from (
select * from testTable order by -id limit 1000000 # 'limit' is required for MariaDB if we want to sort rows in subquery
) t # we have to inverse ids first in order to get this working...
join
( select #rq:= 6 /* example query */, #val:= 1 /* we are going to multiply values */) tmp
where id=#rq
) c where id is null;
Check out Fiddle!
Note! this will not work if row's parent_id>id.
Cheers!
DELIMITER $$
CREATE DEFINER=`arun`#`%` PROCEDURE `recursivesubtree`( in iroot int(100) , in ilevel int(110) , in locid int(101) )
BEGIN
DECLARE irows,ichildid,iparentid,ichildcount,done INT DEFAULT 0;
DECLARE cname VARCHAR(64);
SET irows = ( SELECT COUNT(*) FROM account WHERE parent_id=iroot and location_id=locid );
IF ilevel = 0 THEN
DROP TEMPORARY TABLE IF EXISTS _descendants;
CREATE TEMPORARY TABLE _descendants (
childID INT, parentID INT, name VARCHAR(64), childcount INT, level INT
);
END IF;
IF irows > 0 THEN
BEGIN
DECLARE cur CURSOR FOR
SELECT
f.account_id,f.parent_id,f.account_name,
(SELECT COUNT(*) FROM account WHERE parent_id=t.account_id and location_id=locid ) AS childcount
FROM account t JOIN account f ON t.account_id=f.account_id
WHERE t.parent_id=iroot and t.location_id=locid
ORDER BY childcount<>0,t.account_id;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
OPEN cur;
WHILE NOT done DO
FETCH cur INTO ichildid,iparentid,cname,ichildcount;
IF NOT done THEN
INSERT INTO _descendants VALUES(ichildid,iparentid,cname,ichildcount,ilevel );
IF ichildcount > 0 THEN
CALL recursivesubtree( ichildid, ilevel + 1 );
END IF;
END IF;
END WHILE;
CLOSE cur;
END;
END IF;
IF ilevel = 0 THEN
-- Show result table headed by name that corresponds to iroot:
SET cname = (SELECT account_name FROM account WHERE account_id=iroot and location_id=locid );
SET #sql = CONCAT('SELECT CONCAT(REPEAT(CHAR(36),2*level),IF(childcount,UPPER(name),name))',
' AS ', CHAR(39),cname,CHAR(39),' FROM _descendants');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
END IF;
END$$
DELIMITER ;

MySql: Count amount of times the words occur in a column

For instance, if I have data in a column like this
data
I love book
I love apple
I love book
I hate apple
I hate apple
How can I get result like this
I = 5
love = 3
hate = 2
book = 2
apple = 3
Can we achieve this with MySQL?
Here is a solution only using a query:
SELECT SUM(total_count) as total, value
FROM (
SELECT count(*) AS total_count, REPLACE(REPLACE(REPLACE(x.value,'?',''),'.',''),'!','') as value
FROM (
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.sentence, ' ', n.n), ' ', -1) value
FROM table_name t CROSS JOIN
(
SELECT a.N + b.N * 10 + 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
ORDER BY n
) n
WHERE n.n <= 1 + (LENGTH(t.sentence) - LENGTH(REPLACE(t.sentence, ' ', '')))
ORDER BY value
) AS x
GROUP BY x.value
) AS y
GROUP BY value
Here is the full working fiddle: http://sqlfiddle.com/#!2/17481a/1
First we do a query to extract all words as explained here by #peterm(follow his instructions if you want to customize the total number of words processed). Then we convert that into a sub-query and then we COUNT and GROUP BY the value of each word, and then make another query on top of that to GROUP BY not grouped words cases where accompanied signs might be present. ie: hello = hello! with a REPLACE
If you want to perform such kind of text analysis, I would recommend using something like lucene, to get the termcount for each term in the document.
This query is going to take a long time to run if your table is of any decent size. It may be better to keep track of the counts in a separate table and update that table as values are inserted or, if real time results are not necessary, to only run this query every so often to update the counts table and pull your data from it. That way, you're not spending minutes to get data from this complex query.
Here's what I've for you so far. It's a good start. The only thing you need to do is modify it to iterate through the words in each row. You could use a cursor or a subquery.
Create test table:
create table tbl(str varchar(100) );
insert into tbl values('data');
insert into tbl values('I love book');
insert into tbl values('I love apple');
insert into tbl values('I love book');
insert into tbl values('I hate apple');
insert into tbl values('I hate apple');
Pull data from test table:
SELECT DISTINCT str AS Word, COUNT(str) AS Frequency FROM tbl GROUP BY str;
create a user defined function like this and use it in your query
DELIMITER $$
CREATE FUNCTION `getCount`(myStr VARCHAR(1000), myword VARCHAR(100))
RETURNS INT
BEGIN
DECLARE cnt INT DEFAULT 0;
DECLARE result INT DEFAULT 1;
WHILE (result > 0) DO
SET result = INSTR(myStr, myword);
IF(result > 0) THEN
SET cnt = cnt + 1;
SET myStr = SUBSTRING(myStr, result + LENGTH(myword));
END IF;
END WHILE;
RETURN cnt;
END$$
DELIMITER ;
Hope it helps
Refer This
Split-string procedure is not my job. You can find it here
http://forge.mysql.com/tools/tool.php?id=4
I wrote you the rest of code.
drop table if exists mytable;
create table mytable (
id int not null auto_increment primary key,
mytext varchar(1000)
) engine = myisam;
insert into mytable (mytext)
values ('I love book,but book sucks!What do you,think about it? me too'),('I love apple! it rulez.,No, it sucks a lot!!!'),('I love book'),('I hate apple!!! Me too.,!'),('I hate apple');
drop table if exists mywords;
create table mywords (
id int not null auto_increment primary key,
word varchar(50)
) engine = myisam;
delimiter //
drop procedure if exists split_string //
create procedure split_string (
in input text
, in `delimiter` varchar(10)
)
sql security invoker
begin
declare cur_position int default 1 ;
declare remainder text;
declare cur_string varchar(1000);
declare delimiter_length tinyint unsigned;
drop temporary table if exists SplitValues;
create temporary table SplitValues (
value varchar(1000) not null
) engine=myisam;
set remainder = input;
set delimiter_length = char_length(delimiter);
while char_length(remainder) > 0 and cur_position > 0 do
set cur_position = instr(remainder, `delimiter`);
if cur_position = 0 then
set cur_string = remainder;
else
set cur_string = left(remainder, cur_position - 1);
end if;
if trim(cur_string) != '' then
insert into SplitValues values (cur_string);
end if;
set remainder = substring(remainder, cur_position + delimiter_length);
end while;
end //
delimiter ;
delimiter //
drop procedure if exists single_words//
create procedure single_words()
begin
declare finish int default 0;
declare str varchar(200);
declare cur_table cursor for select replace(replace(replace(replace(mytext,'!',' '),',',' '),'.',' '),'?',' ') from mytable;
declare continue handler for not found set finish = 1;
truncate table mywords;
open cur_table;
my_loop:loop
fetch cur_table into str;
if finish = 1 then
leave my_loop;
end if;
call split_string(str,' ');
insert into mywords (word) select * from splitvalues;
end loop;
close cur_table;
end;//
delimiter ;
call single_words();
select word,count(*) as word_count
from mywords
group by word;
+-------+------------+
| word | word_count |
+-------+------------+
| a | 1 |
| about | 1 |
| apple | 3 |
| book | 3 |
| but | 1 |
| do | 1 |
| hate | 2 |
| I | 5 |
| it | 3 |
| lot | 1 |
| love | 3 |
| me | 2 |
| No | 1 |
| rulez | 1 |
| sucks | 2 |
| think | 1 |
| too | 2 |
| What | 1 |
| you | 1 |
+-------+------------+
19 rows in set (0.00 sec)
The code must be improved in order to consider any punctuation but this is the general idea.