Tokenize a delimited string in MySQL - mysql

I wrote a function in MySQL to split a delimited string into tokens, but right now, it only returns the first token it encounters after the start position (pos). Is there a way to get it to return tokens as a result set with one column containing all of the parsed tokens?
Here is my current function code:
CREATE DEFINER=`root`#`localhost` FUNCTION `split_string_multi_byte`(
source_string VARCHAR(255),
delim VARCHAR(12),
pos INT) RETURNS varchar(255) CHARSET latin1
BEGIN
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(source_string, delim, pos),
CHAR_LENGTH(SUBSTRING_INDEX(source_string, delim, pos -1)) + 1),
delim, "");
END
Here are some parameters that I entered in my Navicat database development and admin client:
That returns the following results:
See how only "1" is returned. I would like to see all of the tokens if possible. However, I'm not sure how to do that.
Any help would be appreciated.
Thanks!
Rob

CREATE DEFINER=`root`#`%` FUNCTION `SPLIT`(s varchar(200), c char, i integer) RETURNS varchar(200) CHARSET utf8mb4
DETERMINISTIC
BEGIN
DECLARE retval varchar(200);
WITH RECURSIVE split as (
select 1 as x,substring_index(substring_index(s,c,1),c,-1) as y, s
union all
select x+1,substring_index(substring_index(s,c,x+1),c,-1),s from split where x<= (LENGTH(s) - LENGTH(REPLACE(s,c,'')))
)
SELECT y INTO retval FROM split WHERE x=i ;
return retval;
END
SELECT SPLIT('a,b,c,d,e,f',',',3); results in 'c'
Because you cannot return a table from a function (in MySQL), you could do something like this if you want results in a table:
SET #tekst = 'aap,noot,mies,wim,zus,jet';
WITH RECURSIVE abc as (
SELECT 1 as c
UNION ALL
SELECT c+1
FROM abc WHERE c<=15)
select c,split(#tekst,',',c) as t
from abc
where not split(#tekst,',',c) is null;
output:
+------+------+
| c | t |
+------+------+
| 1 | aap |
| 2 | noot |
| 3 | mies |
| 4 | wim |
| 5 | zus |
| 6 | jet |
+------+------+

Related

How to update every each rows in different values in MySQL?

id INT | food TEXT | memo TEXT
1 | Cucumbers | NULL
2 | Dandelions | NULL
3 | Salmons | NULL
3 | Cucumbers | NULL
4 | Tomatoes | NULL
Evening.
I have a table called results that splits each food values in several rows like the above.
A column named id refers to an individual animal, and a column food is an object what the animals would eat.
I would like to fill up a column memo by using REPLACE or UPDATE keywords like this:
3 | Salmons | Mostly liked it, only 15% didn't eat.
3 | Cucumbers | Only 10% have eaten, rest of all didn't even try.
A problem is MySQL always updates the same line like this:
3 | Salmons | Mostly liked it, only 15% didn't eat.
3 | Cucumbers | Mostly liked it, only 15% didn't eat.
This is my progress:
DROP FUNCTION IF EXISTS fx_length;
DROP FUNCTION IF EXISTS fx_splitter;
DROP FUNCTION IF EXISTS fx_split_row;
DROP PROCEDURE IF EXISTS App_forEach_memo;
DELIMITER //
CREATE FUNCTION fx_length(str TEXT, del VARCHAR(2), pos INT)
RETURNS INT
RETURN LENGTH(SUBSTRING_INDEX(str, del, pos - 1)) + 1 //
CREATE FUNCTION fx_splitter(str TEXT, del VARCHAR(2), pos INT)
RETURNS TEXT
RETURN SUBSTRING(SUBSTRING_INDEX(str, del, pos), fx_length(str, del, pos)) //
CREATE FUNCTION fx_split_row(str TEXT, del VARCHAR(2), pos INT)
RETURNS TEXT
BEGIN
DECLARE output TEXT;
SET output = REPLACE(fx_splitter(str, del, pos), del, '');
IF output = '' THEN SET output = NULL; END IF;
RETURN output;
END //
CREATE PROCEDURE App_forEach(IN target INT, strings TEXT)
BEGIN
DECLARE i INT DEFAULT 1;
REPEAT
UPDATE results
SET id = target, memo = fx_split_row(strings, '| ', i)
WHERE id = target;
SET i = i + 1;
UNTIL i = target
END REPEAT;
END //
DELIMITER ;
CALL App_forEach(3, "Mostly liked it, only 15% didn't eat.| Only 10% have eaten, rest of all didn't even try.");
I think I need to change this part SET id = target . . . for counting per same id numbers, but I don't know how to do this.
Are there any ways to update the memo values w/o creating an extra temp table?
Any tips, suggestions and answers for resolving this problem would be huge appreciated.
Thanks.
WITH cte AS ( SELECT food, ROW_NUMBER() OVER () rn
FROM results
WHERE #id = id )
UPDATE results, cte
SET results.memo = TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(#memo, '|', cte.rn), '|', -1))
WHERE results.food = cte.food
AND results.id = #id
AND cte.rn <= 1 + LENGTH(#memo) - LENGTH(REPLACE(#memo, '|', ''));
fiddle
You may put this query into a procedure if needed.
If you have ancient MySQL version which does not support CTE and window functions then emulate them in subquery using user-defined variables.

Srtange result from mysql function

I create a function that returns a value, selected in a periods table like this:
CREATE TABLE `periods` (
`period` DATE NOT NULL,
`threshold` DOUBLE NOT NULL,
PRIMARY KEY (`period`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB;
+------------------------+
| periods |
+------------+-----------+
| period | threshold |
+------------+-----------+
| 2013-11-01 | 5 |
+------------+-----------+
| 2013-12-01 | 1 |
+------------+-----------+
| 2014-01-01 | 5 |
+------------+-----------+
| 2014-02-01 | 5 |
+------------+-----------+
And function create:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `GET_THRESHOLD`(`PERIOD` VARCHAR(10))
RETURNS double
LANGUAGE SQL
NOT DETERMINISTIC
READS SQL DATA
SQL SECURITY DEFINER
COMMENT 'RETURN THRESHOLD'
BEGIN
DECLARE RESULT DOUBLE;
SELECT threshold INTO RESULT FROM periods WHERE period = PERIOD LIMIT 1;
RETURN RESULT;
END
$$
DELIMITER ;
but the function returns a value the Wrong
mysql>SELECT GET_THRESHOLD('2013-12-01')
-> 5
someone can help me?
You parameter has the same name as a column. That's a no-no. Try this:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `GET_THRESHOLD`(`V_PERIOD` VARCHAR(10))
RETURNS double
LANGUAGE SQL
NOT DETERMINISTIC
READS SQL DATA
SQL SECURITY DEFINER
COMMENT 'RETURN THRESHOLD'
BEGIN
DECLARE RESULT DOUBLE;
SELECT threshold INTO RESULT FROM periods WHERE period = V_PERIOD LIMIT 1;
RETURN RESULT;
END
$$
DELIMITER
The statement:
WHERE period = PERIOD
is comparing the column value to itself. So, it chooses all rows that have a non-NULL column value. Not very interesting.
It is good practice to always prefix variables and arguments with something to distinguish them from columns in tables.

how to call a stored procedure using table data?

i want to create a stored procedure by using below requirement.
i tried and written a stored procedure it is working fine with the static values.
how a stored procedure will work with the dynamic values.
Please find my requirement here.
Create a stored proc “skillsparse” that accepts a string of text and and breaks it up into 1,2,3 word phrases.
a. For example: I love java because it’s fun should have these 15 phrases
i. I
ii. I love
iii. I love java
iv. Love
v. Love java
vi. Love java because
vii. Java
viii. Java because
ix. Java because it’s
x. Because
xi. Because it’s
xii. Because it’s fun
xiii. It’s
xiv. It’s fun
xv. fun
3. Store these phrases in a new table called: github_skills_phrases with fields: ID, userid, skills_id (from github_skills_source) and skills_phrase
4. Create a storedproc that compares the skills_phrases against the skills table (ref Table) and store the values into the github_skills table for each user. If possible, please maintain the source of where the skills came from (repodesc, repolang, starred, bio)
5. NOTE: Aside from the info in the new table Kishore is creating, you will also need to run the github_users.bio field against the Skillsparse procedure. You can start this first (for testing logic, etc) since the github_users.bio already exists and has data.
We don’t need to go this for users who have not yet been processed for skills
How i written is:
++++++++++++++++++++++++++++++++++++++++++++++++++++++
DELIMITER $$
CREATE procedure testing(IN id varchar(20),IN usr_id varchar(20),IN str varchar(200))
begin
DECLARE wordCnt varchar(20);
DECLARE wordCnt1 varchar(20);
DECLARE idx INT DEFAULT 1;
DECLARE splt varchar(200);
declare strng varchar(200);
create temporary table tmp.hello1(id varchar(200),usr_id varchar(200),st varchar(200));
set strng = str;
set wordCnt = LENGTH(trim(strng)) - LENGTH(REPLACE(trim(strng), ' ', ''))+1;
set wordCnt1 = LENGTH(trim(strng)) - LENGTH(REPLACE(trim(strng), ' ', ''))+1;
myloop: WHILE idx <= wordCnt DO
set splt = substring_index(trim(strng),' ',idx);
insert into tmp.hello1 values (id,usr_id,splt);
set idx=idx+1;
IF idx = 4 THEN
set strng = substring(trim(strng),length(substring_index(trim(strng),' ',1))+1);
set idx = 1;
set wordCnt = wordCnt -1;
END IF;
end while ;
insert into tmp.hello1 values (id,usr_id,trim(substring(trim(str),length(substring_index(trim(str),' ',wordCnt1-1))+1)));
end $$
Out put ::
mysql> call testing('10','200','I am the my fine the kks hhh nanj kell');
Query OK, 1 row affected (0.77 sec)
mysql> select * from hello1;
+------+--------+---------------+
| id | usr_id | st |
+------+--------+---------------+
| 10 | 200 | I |
| 10 | 200 | I am |
| 10 | 200 | I am the |
| 10 | 200 | am |
| 10 | 200 | am the |
| 10 | 200 | am the my |
| 10 | 200 | the |
| 10 | 200 | the my |
| 10 | 200 | the my fine |
........
..........
| 10 | 200 | kell |
+------+--------+---------------+
27 rows in set (0.00 sec)
my stored procedure is working fine with static values .how to call dynamically a stored procdure by using table data.
Please help me to write a stored procedure to calling with the table data.
If you means you need to call this stored procedure inside select statement on certain data table, this is not available.
You have two options:
1- transfer your procedure to function and then you can call it easily from inside the select statement.
2- write plsql code to call this procedure and you can check the below link about this point
oracle call stored procedure inside select

How to get frequency of a word in a row using mysql fulltext

I have a MyISAM table comprising over 2 million records, on which there is a FULLTEXT index over multiple columns.
Given a search term, I would like to know how many times it occurs within the indexed fields of each record.
For example, when searching for 'test' within the following table (in which there is a FULLTEXT index over both the FREETEXT and Third_Col columns):
+----+--------------------------------------------+---------------------------+
| ID | FREETEXT | Third_Col |
+----+--------------------------------------------+---------------------------+
| 1 | This is first test string in test example. | This is first test Values |
| 2 | This is second test. | This is sec col |
+----+--------------------------------------------+---------------------------+
I expect results like:
+----+-------+
| ID | count |
+----+-------+
| 1 | 3 |
| 2 | 1 |
+----+-------+
I know that in the FULLTEXT index MySQL uses dtf (the number of times the term appears in the document); how can one obtain this?
Create a user defined function like this
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 ;
Then you can use this in your query as follows
select id, getCount(concat(FREETEXT, Third_col), 'test') from yourtable
Hope it helps

Mysql:Query for the table as below

I have the following table:
|-------------------|
| id | Homephone |
|-------------------|
| 1 | 454454125 |
| 2 | 47872154587 |
| 3 | 128795423 |
| 4 | 148784474 |
|-------------------|
I have around 40.000 rows in the table.
I want to format Homephone values as following:
454-454-125
478-721-545-87
128-795-423
148-784-474
i.e. after every 3 numbers I want - (hyphen).
How to achieve this using MySQL?
You need to wite a udf for this
Basically, you need to create your own function (so called UDF - User Defined Function) and run it on the table.
There is a nice function by Andrew Hanna posted in String Functions chapter of the MySQL Reference Manual. I fixed a small mistake there (replaced WHILE (i < str_len) DO by WHILE (i <= str_len) DO.
There are two steps (two SQL queries):
Create the function. It has three parameters: str - the string to be modified, pos - position of the character being inserted into the string, delimit - character(s) to be inserted:
DELIMITER //
CREATE FUNCTION insert_characters(str text, pos int, delimit varchar(124))
RETURNS text
DETERMINISTIC
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE str_len INT;
DECLARE out_str text default '';
SET str_len = length(str);
WHILE (i <= str_len) DO
SET out_str = CONCAT(out_str, SUBSTR(str, i, pos), delimit);
SET i = i + pos;
END WHILE;
-- trim delimiter from end of string
SET out_str = TRIM(trailing delimit from out_str);
RETURN(out_str);
END//
DELIMITER ;
Run the function...
...for testing purpose (select, no update):
SELECT insert_characters(Homephone, 3, "-") AS new_phone FROM my_table;
...to update the records:
UPDATE my_table SET Homephone = insert_characters(Homephone, 3, "-");
Please try to analyze the function line by line. This example may help you to understand the subject.