MySql Query to convert columns containing delimeter into rows - mysql

Basically I need to write a query to select the below table
UID | Col A | Col B
123 x;y;z v;b
into the below requirement format.
123 , Col A, X
123 , Col A, y
123 , Col A, z
123 , Col B, v
123 , Col B, b
Any suggestions are really appreciated.

This is a pain, but here is one method:
select uid, 'Col A' as col,
substring_index(substring_index(colA, ';', n.n), ';', -1) as val,
from t cross join
(select 1 as n union all select 2 union all select 3
) n
on (length(replace(colA, ';', '; ')) - length(colA)) <= n.n + 1
union all
select uid, 'Col B' as col,
substring_index(substring_index(colB, ';', n.n), ';', -1) as val,
from t cross join
(select 1 as n union all select 2 union all select 3
) n
on (length(replace(colB, ';', '; ')) - length(colB)) <= n.n + 1;

Related

MYSQL Split String and Duplicate Row

I have a Mysql table That looks like this:
Col 1. Col 2.
a 1
b 2
c,d,e 3
What I would like to do is run a query that would replace the row with c,d,e with multiple broken out rows so that the result for Select * From table would look like:
Col 1. Col 2.
a 1
b 2
c 3
d 3
e 3
If you know the maximum number, you can use union all:
select substring_index(col1, ',', 1) as col1, col2
from t
union all
select substring(substring_index(col1, ',', 2), ',', -1) as col1, col2
from t
where col1 like '%,%'
union all
select substring(substring_index(col1, ',', 3), ',', -1) as col1, col2
from t
where col1 like '%,%,%';
Use a tally table. For example, mine is generated on the fly by recursive CTE
with recursive nmbs as (
select 1 n
union all
select n+1
from nmbs
where n<100
),
testdata as (
select 'a' c1, 1 c2 union all
select 'b' c1, 2 c2 union all
select 'c, ddd , e ,fgh' c1, 3
)
select c1, c2, trim(replace(substring(substring_index(c1, ',', n), length(substring_index(c1, ',', n-1))+1), ',', '')) s
from testdata
join nmbs on n <= 1 + length(c1) - length(replace(c1,',',''))
order by c1,n
db<>fiddle

MySQL - Split Delimited Right and Left Values

I have a case where I will get input for products and their values separated with a delimited special character. Using this string I need to separate products and their values to MySQL Rows like below.
Input:
{"1301":29.00,"1302":25.01,"1306":50.09,"1678":100.00}
Output:
Product ID Value
1301 29.00
1302 25.01
1306 50.09
1678 100.00
Here the products Id counts are dynamic, we can get n count every time. Please help me getting the above output in MySQL.
MySQL only solution with JSON functions.
Query
SELECT
TRIM(REPLACE(
SUBSTRING_INDEX(
SUBSTRING_INDEX(json_parsed, ',', number_generator.number)
, ','
, -1
)
, '"'
, ''
)) AS 'Product ID'
, JSON_EXTRACT(json, CONCAT('$.', SUBSTRING_INDEX(
SUBSTRING_INDEX(json_parsed, ',', number_generator.number)
, ','
, -1
))) AS 'Value'
FROM (
SELECT
#row := #row + 1 AS number
FROM (
SELECT 0 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
) row1
CROSS JOIN (
SELECT 0 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
) row2
CROSS JOIN (
SELECT #row := 0
) init_user_params
) AS number_generator
CROSS JOIN (
SELECT
SUBSTRING(json_keys, 2, json_keys_length - 2) AS json_parsed
, json_keys
, json
, JSON_LENGTH(json_keys) AS json_array_length
FROM (
SELECT
JSON_KEYS(record.json) AS json_keys
, json
, LENGTH(JSON_KEYS(record.json)) AS json_keys_length
FROM (
SELECT
'{"1301":29.00,"1302":25.01,"1306":50.09,"1678":100.00}' AS json
FROM
DUAL
) AS record
) AS json_information
) AS json_init
WHERE
number_generator.number BETWEEN 0 AND json_array_length
Result
| Product ID | Value |
| ---------- | ----- |
| 1301 | 29.0 |
| 1302 | 25.01 |
| 1306 | 50.09 |
| 1678 | 100.0 |
see demo
You really should be treating this like JSON, but you can use brute-force string methods. Here is one method:
select replace(substring_index(str, ':', 1), '"', '') as product_id, substring_index(str, ':', -1) as value
from (select replace(replace(substring_index(#x, ',', 1), '{', ''), '}', '') as str) x
union all
select replace(substring_index(str, ':', 1), '"', '') as product_id, substring_index(str, ':', -1) as value
from (select replace(replace(substring_index(substring_index(#x, ',', 2), ',', -1), '{', ''), '}', '') as str) x
union all
select replace(substring_index(str, ':', 1), '"', '') as product_id, substring_index(str, ':', -1) as value
from (select replace(replace(substring_index(substring_index(#x, ',', 3), ',', -1), '{', ''), '}', '') as str) x
union all
select replace(substring_index(str, ':', 1), '"', '') as product_id, substring_index(str, ':', -1) as value
from (select replace(replace(substring_index(substring_index(#x, ',', 4), ',', -1), '{', ''), '}', '') as str) x;
along with a db<>fiddle.

Fetching Only Unique Results From Sql Database

Database Table
ID Post Tags
1 Range rover range-rover,cars
2 Lamborghini lamborghini,cars
3 Kawasaki kawasaki,bikes
4 Yamaha R1 yamaha,r1,bikes
I Want to Remove Duplicate Values from Result sql
What i Get When i fetch tags (tags are in ,) from Database
SELECT Tags from posts;
Resut:
range-rover,cars lamborghini,cars kawasaki,bikes yamaha,r1,bikes
What I Need is not to show same result again.
range-rover,cars lamborghini kawasaki,bikes yamaha,r1
You can split your text using tally table and SUBSTRING_INDEX:
SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(t.tags, ',', n.n), ',', -1) AS val
FROM posts 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
) n
WHERE n.n <= 1 + (LENGTH(t.tags) - LENGTH(REPLACE(t.tags, ',', '')))
SqlFiddleDemo
If you need one row add GROUP_CONCAT:
SELECT GROUP_CONCAT(DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(t.tags, ',', n.n), ',', -1)) AS val
...
SqlFiddleDemo2

How to select only particular word start with # from sentence mysql query

let's explain briefly
this is very new topic, I want to fetch only particular word start with # from sentence for example
i have sentence like
Hi Majjx Uxud Xhhxhd Hx Dhx #hdhd Jdhhdhshhfd Hxhhd #bhd Hxhd Hxhhd Dhhdh www.myinnos.in Hdhd Xfhhxhd Xhhdh Xhx 9560233669 ndhdh Hxhhdh Dhh
from above sentence I have to fetch #hdhd
got a solution for my question, now I want to count and show the repeated words as count
select val from(
select (substring_index(substring_index(a, ' ', n.n), ' ', -1)) val
from (select id, message as a from filmbooknewsfeed) t
cross join(
select a.n + b.n * 10 + 1 n
from
(select 0 as n 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
) a,
(select 0 as n 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 n
) n
where n.n <= 1 + (length(t.a) - length(replace(t.a, ' ', '')))
order by val asc
)x where val like '#%'
As I said, you need to convert the sentence into rows. Just in case, if in sentence you have more than 1 words start with #.
select val from(
select (substring_index(substring_index(a, ' ', n.n), ' ', -1)) val
from (
select 'Hi Majjx Uxud Xhhxhd Hx Dhx #hdhd Jdhhdhshhfd Hxhhd #bhd Hxhd Hxhhd Dhhdh www.myinnos.in Hdhd Xfhhxhd Xhhdh Xhx 9560233669 ndhdh Hxhhdh Dhh' as a
) t
cross join(
select a.n + b.n * 10 + 1 n
from
(select 0 as n 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
) a,
(select 0 as n 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 n
) n
where n.n <= 1 + (length(t.a) - length(replace(t.a, ' ', '')))
order by val asc
)x where val like '#%'
Will give you #hdhd. even if you has more than 1 # in the sentence. This would give you correct result.
edit
If you want to group by result and sort by most occurence words like twitter tranding topic, modify your query like this (as query on the question)
select val,count(val) as cnt from(
select (substring_index(substring_index(a, ' ', n.n), ' ', -1)) val
from (select id, message as a from filmbooknewsfeed) t
cross join(
select a.n + b.n * 10 + 1 n
from
(select 0 as n 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
) a,
(select 0 as n 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 n
) n
where n.n <= 1 + (length(t.a) - length(replace(t.a, ' ', '')))
order by val asc
)x where val like '#%'
group by val
order by cnt desc
You can do this using substring_index():
select substring_index(substring_index(substring_index(sentence, '#', 2), '#', -1), ' ', 1)

Split single VARCHAR field with many values, and insert them separately

I'm migrating an old database data to a new one, and they used to store telephone numbers in the following format:
Example 1:
41.9044-9082;41.9044-9661;41.9851-9862;41.9984-0393;41.3399-9169;41.3997-7999;
Example 2:
41.3369-0102;41.8928-5992;
No telephones(empty):
;
How can I split these single VARCHAR fields with many values, and insert them separately?
Table example of how it is:
|#id_tel#|### number ####|#|client_id|#|
|# 1 #|111163;3554353;|#| 2 |#|
|# 2 #|222222; |#| 3 |#|
|# 3 #|; |#| 4 |#|
Table example of how I would like it to be:
|#id_tel#|### number ####|#|client_id|#|
|# 1 #|111163 |#| 2 |#|
|# 2 #|3554353 |#| 2 |#|
|# 3 #|222222 |#| 3 |#|
You could do that with nested calls of SUBSTRING_INDEX() and a numbers table. In my example I create the numbers table on the fly for up to 100 numbers.
Assuming a table old_tel with following CREATE TABLE statement:
CREATE TABLE old_tel (
id_tel INT,
`number` VARCHAR(200),
client_id INT
);
you get the splitted numbers with the client_id with this query:
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(`number`, ';', n.n), ';', -1) value,
client_id
FROM
old_tel
CROSS JOIN (
SELECT
1 + a.N + b.N * 10 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
ORDER BY n
) n
WHERE
n.n <= LENGTH(`number`) - LENGTH(REPLACE(`number`, ';', ''))
AND
SUBSTRING_INDEX(SUBSTRING_INDEX(`number`, ';', n.n), ';', -1) <> ''
ORDER BY
client_id, SUBSTRING_INDEX(SUBSTRING_INDEX(`number`, ';', n.n), ';', -1);
Assuming your new telephone numbers table looks nearly the same:
CREATE TABLE new_tel (
id_tel INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`number` VARCHAR(200),
client_id INT
);
you can fill this table with this simple INSERT statement using the first query:
INSERT INTO new_tel (`number`, client_id)
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(`number`, ';', n.n), ';', -1) value,
client_id
FROM
old_tel
CROSS JOIN (
SELECT
1 + a.N + b.N * 10 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
ORDER BY n
) n
WHERE
n.n <= LENGTH(`number`) - LENGTH(REPLACE(`number`, ';', ''))
AND
SUBSTRING_INDEX(SUBSTRING_INDEX(`number`, ';', n.n), ';', -1) <> ''
ORDER BY
client_id, SUBSTRING_INDEX(SUBSTRING_INDEX(`number`, ';', n.n), ';', -1);
Explanation
The inner subselect with the UNION ALL creates on the fly a numbers table. We restrict this on the number of substrings in the number column and filter out empty values.
SUBSTRING_INDEX(SUBSTRING_INDEX(`number`, ';', n.n), ';', -1) value
cuts out the n-th number that is separated by semicolon.
See it working in this Demo
**Note: ** This is very fast by avoiding agonizing row by row inserts.