Also possible using PREPARED STATEMENT
SET @sql := NULL;
SET @sql := (SELECT CONCAT('SELECT ROW_NUMBER() OVER (ORDER BY id_suboperation,
id_element) AS id,
id_suboperation, id_element
FROM (',GROUP_CONCAT(qv SEPARATOR ' union all '),' ) sq
GROUP BY id_suboperation, id_element
ORDER BY id_suboperation, id_element;')
FROM
(SELECT CONCAT("SELECT id AS id_suboperation,
SUBSTRING_INDEX(
SUBSTRING_INDEX(
REPLACE(subOperation,'test',''),',',",idx,"),',',-1) AS id_element
FROM mytable") qv FROM mytable a CROSS JOIN
(WITH RECURSIVE wordCount AS (
SELECT 1 IDX,
(LENGTH(subOperation)-LENGTH(REPLACE(subOperation,',','')))+1 AS MAXCOUNT
FROM mytable UNION ALL
SELECT IDX+1, MAXCOUNT FROM wordCount WHERE IDX+1 <= MAXCOUNT)
SELECT IDX FROM wordCount
GROUP BY IDX) b
GROUP BY qv) c);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
At least with new data being added, you don't need to change the statement.
P/S: I personally like @nayi224's answer though.
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=8a1f8142fdc9a66b72a455e3451029bf
Update:
For older MySQL version that don't support WITH
and ROW_NUMBER()
:
SET @sql := NULL;
SET @sql := (SELECT CONCAT('SELECT (@rownum := @rownum+1) AS Rownum,
id_suboperation, id_element
FROM
(SELECT *
FROM (',GROUP_CONCAT(qv SEPARATOR ' union all '),' ) sq
GROUP BY id_suboperation, id_element) vr
CROSS JOIN (SELECT @rownum := 0) rn
ORDER BY id_suboperation, id_element;')
FROM
(SELECT CONCAT("SELECT id AS id_suboperation,
SUBSTRING_INDEX(
SUBSTRING_INDEX(
REPLACE(subOperation,'test',''),',',",idx,"),',',-1) AS
id_element
FROM mytable") qv FROM mytable a CROSS JOIN
(SELECT 1 IDX UNION
SELECT 2 UNION
SELECT 3 UNION
SELECT 4) b
GROUP BY qv) c);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
This will return @sql
as following:
SELECT (@rownum := @rownum+1) AS Rownum, id_suboperation, id_element
FROM (SELECT * FROM (SELECT id AS id_suboperation,
SUBSTRING_INDEX(
SUBSTRING_INDEX(
REPLACE(subOperation,'test',''),',',1),',',-1) AS id_element
FROM mytable union all SELECT id AS id_suboperation,
SUBSTRING_INDEX(
SUBSTRING_INDEX(
REPLACE(subOperation,'test',''),',',2),',',-1) AS id_element
FROM mytable union all SELECT id AS id_suboperation,
SUBSTRING_INDEX(
SUBSTRING_INDEX(
REPLACE(subOperation,'test',''),',',3),',',-1) AS id_element
FROM mytable union all SELECT id AS id_suboperation,
SUBSTRING_INDEX(
SUBSTRING_INDEX(
REPLACE(subOperation,'test',''),',',4),',',-1) AS id_element
FROM mytable ) sq
GROUP BY id_suboperation, id_element) vr
CROSS JOIN (SELECT @rownum := 0) rn
ORDER BY id_suboperation, id_element;
As for your question "And also, what happens when all the words don't start with test?" , if the string value is consistent, then you can just replace test
with a different word from this part:
....
REPLACE(subOperation,'test',''),',',",idx,"),',',-1) AS id_element
^^^^
here
....
If the string parts are not consistent but the numerical value is always at the end, you may try using REVERSE()
with CAST
or just REVERSE(REVERSE(string)+0)
. The conversion from string to numbers only I referred from this answer . So, the query for setting @sql
might be something like this at the end:
SET @sql := (SELECT CONCAT('SELECT ROW_NUMBER() OVER (ORDER BY id_suboperation,
id_element) AS id,
id_suboperation, id_element
FROM (',GROUP_CONCAT(qv SEPARATOR ' union all '),' ) sq
GROUP BY id_suboperation, id_element
ORDER BY id_suboperation, id_element;')
FROM
(SELECT CONCAT("SELECT id AS id_suboperation,
REVERSE(REVERSE(SUBSTRING_INDEX(
SUBSTRING_INDEX(subOperation,',',",idx,"),',',-1))+0) AS id_element
FROM mytable") qv FROM mytable a CROSS JOIN
(SELECT 1 IDX UNION
SELECT 2 UNION
SELECT 3 UNION
SELECT 4) b
GROUP BY qv) c);
The REVERSE()
function is repeated because if the string value is like this test53
, the first reverse will make it as 35tset
. Then after using CAST()
or +0
on it, the number value will become 35
instead of 53
from the original string value. Therefore, to get the correct number from the original string, it has to be reversed again.
Updated fiddle