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
Related
column1 | column2 | Result
32,33 | A,B | A32,A33,B32,B33
I have given an example above In which I have two columns with multiple values separated by a comma and I want to merge the first two columns and want to get a result as shown in the Result column.
On MySQL 8.0, You can first split the columns on the basis of comma separated values -
with recursive col1 as (select 1 id, '32,33' as column1
union all
select 2, '34,35'),
rec_col1 as (select id, column1 as remain, substring_index( column1, ',', 1 ) as column1
from col1
union all
select id, substring( remain, char_length( column1 )+2 ),substring_index( substring( remain, char_length( column1 ) +2 ), ',', 1 )
from rec_col1
where char_length( remain ) > char_length( column1 )
RESULT
id column1
1 32
1 33
2 34
2 35
Similarly, Second column -
with recursive col2 as (select 1 id, 'A,B' as column2
union all
select 2, 'C,D'),
rec_col2 as (select id, column2 as remain, substring_index( column2, ',', 1 ) as column2
from col2
union all
select id, substring( remain, char_length( column2 )+2 ),substring_index( substring( remain, char_length( column2 ) +2 ), ',', 1 )
from rec_col2
where char_length( remain ) > char_length( column2 ))
select id, column2 from rec_col2
order by id;
RESULT
id column2
1 A
1 B
2 C
2 D
After splitting both the columns, You can join them on the basis of id -
select concat(c2.column2, c1.column1) result_rows
from rec_col1 c1
join rec_col2 c2 on c1.id = c2.id
RESULT
result_rows
A32
B32
C34
D34
A33
B33
C35
D35
Finally you can use GROUP_CONCAT to combine them -
select group_concat(c2.column2, c1.column1 order by c2.column2, c1.column1) result
from rec_col1 c1
join rec_col2 c2 on c1.id = c2.id
group by c2.id
RESULT
result
A32,A33,B32,B33
C34,C35,D34,D35
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;
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
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.
I have a input variable
#inputData varchar(Max)
e.g :
Victor:2;John:22;Jo:100
how can I split the variable into two columns?
Col1 Col2
----------
Victor 2
John 22
Jo 100
Here is the script, this gives multiple columns and rows from single string value.
declare #inputData varchar(Max) = 'Victor:2;John:22;Jo:100' + ';'
;with row(c1,c2)
as
(
SELECT LEFT
( #inputData
, CHARINDEX(';', #inputData, 0) - 1
) col1
, SUBSTRING
( #inputData
, CHARINDEX(';', #inputData, 0) + 1
, LEN(#inputData)
) col2
UNION ALL
SELECT LEFT
( c2
, CHARINDEX(';', c2, 0) - 1
) col1
, SUBSTRING
( c2
, CHARINDEX(';', c2, 0) + 1
, LEN(c2)
) col2
FROM row
WHERE CHARINDEX(';', c2, 0) >0
)
select LEFT(C1, CHARINDEX(':', c1, 0) - 1) col1, SUBSTRING( c1 , CHARINDEX(':', c1, 0) + 1, LEN(c1)) col2 from row
Output :
col1 col2
Victor 2
John 22
Jo 100
May not be a very good/efficient solution and typically based on your example; you can try the below:
create table tab1(col varchar(100))
insert into tab1 values ('key1:val1;key2:val2;key3:valu3')
Query:
select SUBSTRING((SUBSTRING((left(col,CHARINDEX(';',Col))),0,
charindex(';',col))),0,charindex(':',col)) as Name,
SUBSTRING((SUBSTRING((left(col,CHARINDEX(';',Col))),0,
charindex(';',col))),(charindex(':',col)+1),4) as Age
from tab1
union
select SUBSTRING((SUBSTRING(right(col,CHARINDEX(';',Col)),0,
charindex(';',col))) ,0,charindex(':',col)) as Name,
SUBSTRING((SUBSTRING(right(col,CHARINDEX(';',Col)),0,
charindex(';',col))),(charindex(':',col)+1),4) as Age
from tab1
union
select SUBSTRING((SUBSTRING(substring(col,(CHARINDEX(';',Col) +
1),10),0,charindex(';',col))),0,charindex(':',col)) as Name,
SUBSTRING((SUBSTRING(substring(col,(CHARINDEX(';',Col) + 1),10),0,
charindex(';',col))),(charindex(':',col)+1),4) as Age
from tab1
The best way to achieve this would be UDF (user Defined Functions). This is just a
example and you may like to take it further from here.