MySql : Convert Column data to row - mysql

I have a table in mysql which looks like below.
id cust_id date data
1 1 1/1/2018 a b c d e f g
2 1 2/1/2018 h I j k l m n
Here in this example data column is having huge data seperated by space like a b c d, I would like to show case as in row like below
id cust_id date data
1 1 1/1/2018 a
1 1 1/1/2018 b
1 1 1/1/2018 c
1 1 1/1/2018 d
2 2 2/1/2018 h
2 2 2/1/2018 i
2 2 2/1/2018 j
2 2 2/1/2018 k
I have checked few option like using unpivot function, but unable to achieve my output.
Thanks in advance !!

select
tablename.id,
tablename.date
,SUBSTRING_INDEX(SUBSTRING_INDEX(tablename.data, ' ', numbers.n), ' ', -1) name
from
(
SELECT #row := #row + 1 as n FROM
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t1,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2,
(SELECT #row:=0) r
) numbers INNER JOIN Table1 tablename
on CHAR_LENGTH(tablename.data)
-CHAR_LENGTH(REPLACE(tablename.data, ' ', ''))>=numbers.n-1
order by
id, n
Check link for output
http://sqlfiddle.com/#!9/fa0dcb/1
EXPLANATION:
First go through the inner query i.e.
select 0
union all
select 1
union all
select 3
union all
select 4
union all
select 5
union all
select 6
union all
select 6
union all
select 7
union all
select 8
union all
select 9
This will generate a table of 10 rows with 10 numbers.
Now the other query :
SELECT #row := #row + 1 as n FROM
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t1
Since above query is generating row numbers from below table 't' and table 't1' which is separated by ',' means that they are producing Cartesian product of their total rows.
For example: t have 10 rows and t1 also have 10 rows so, there Cartesian product produces 100 rows. So #row variable incremented 100 times and gives 100 rows of 100 numbers from 1 to 100.
The below query:
SUBSTRING_INDEX(SUBSTRING_INDEX(tablename.data, ' ', numbers.n), ' ', -1)
this one will take "a b c d e f g h" one by one.
For example:
take numbers.n = 1
then inner substring_index will find index of first space and will return string before that index i.e. 'a'
and then outer substring_index will find the space from the end of the resulting string and will give the last character from the string i.e. 'a'.
Now if you
take numbers.n = 2
then inner substring_index will find index of first space and will return string before that index i.e. 'a b'
and then outer substring_index will find the space from the end of the resulting string and will give the last character from the string i.e. 'b'
Always try to breakdown the query like this and you will able to understand the query in simpler way.

Related

mysql select odd number values in a column that includes delimiter separated values

My next database table will be set up more optimally. Unfortunately this one was already set up where one column [data] contains checkbox array values that were saved the following way:
value 1|~|value 1 value 2|~|value 2 value 3|~|value 3
Not optimal, I know.
What I need is a mysql query that select only the values in [data] column in front of the |~|. Basically think I need to select the only odd values.
Any help pointing me in the right direction is greatly appreciated. I tried an if statement in a query and it did not work. Of course I deleted that by mistake.
What I need is a mysql query that select only the
values in [data] column in front of the |~|.
One thing to note the numbers before |~| must be unique.
It will not show the same number twice.
Query
SELECT
DISTINCT
SUBSTRING (
record_data.column
, LOCATE('|~|', record_data.`column` , number_generator.number) - 1
, 1
) AS number
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
) record_1
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
) record_2
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
) record_4
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
) record_5
CROSS JOIN (
SELECT #row := 0
) AS init_user_params
) AS number_generator
CROSS JOIN (
SELECT
*
FROM (
SELECT 'value 1|~|value 1 value 2|~|value 2 value 3|~|value 3' AS `column`
) AS record
) AS record_data
WHERE
LOCATE('|~|', record_data.`column` , number_generator.number) <> 0
Result
| number |
| ------ |
| 1 |
| 2 |
| 3 |
demo

How to split string token and group by count them in mysql?

How to split the string and grouping them by splited token?
I want to get that grouping splited token's each count.
I have a varchar column and it store a string which can split by ',' .
below is the row data of the column. (column name is LogData)
[LogData]
1,2,3,4
1,3,1,9
2,1,3
6,2
And then i want to show(select) like below.
[token] [count]
1 : 4
2 : 3
3 : 3
4 : 1
6 : 1
9 : 1
If possible, then may i have a answer about this with some explanation? (I'm not skilled in db)
Using the and adapting the comment from undefined_variable the correct query looks like this:
SELECT value,COUNT(*) FROM
(SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t0.logdata, ',', n.n), ',', -1) value
FROM t0 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(t0.logdata) - LENGTH(REPLACE(t0.logdata, ',', '')))
ORDER BY value) nt0 GROUP BY value

How do I create a MySQL function to output a query that has values from 1 to a given number?

I am bit new to MySQL. I am trying to create a mysql function that will produce and output a query with a single column with values from 1 to that given number.
Start of the function looks like,
create function get_NumberSequence (n)
Suppose I call the function as,
select get_NumberSequence(5);
I should get the output like below.
Sequence
--------
1
2
3
4
5
I tried an approach to combine and store queries like,
#num:=(select 1 as Sequence)
#num:=#num union (select 2 as Sequence)
This didn't work for me.
This is for case that your input number l_input_number < 10^4 (10000).
You could change your query with larger input number
SELECT #row := #row + 1 as sequence
FROM
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t3,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t4,
(SELECT #row:=0) t_init
LIMIT 17; --LIMIT l_input_number;
And use IF ELSE STATEMENT for each query of input number range for better performance
IF l_input_number < 1000
THEN --only use query up to t3
ELSEIF l_input_number < 10000
THEN --use query up to t4
ELSEIF l_input_number < 100000
THEN --use query up to t5
--etc........
END IF;

INSERT rows multiple times based on a column value from another table

Mainly, I would like to insert a row in table 1 multiple times, based on an integer value in a column of table 2.
My situation
Table 2 contains a column 'SKU' and 'stock', and I would like to insert the 'SKU' and a timestamp into table 1. I want this row duplicated for 'stock'-value times in table 1.
I currently have the following query:
DECLARE #Count int = 1
WHILE #Count <= ....
BEGIN
INSERT INTO table1 (table1.SKU, table1.timestamp_in)
SELECT table2.SKU, "some timestamp" FROM table2
SET ...
END
I am not sure if this is the correct approach. I would like to run this loop for 'table2.stock' times.
My question is: Is this possible with just a SQL query, or should it be a better practice to build some (in my case) java code for this?
You don't need a procedure or anything like that. All you need is a table containing just numbers. I'm creating this table on the fly with this in this example:
SELECT aa.a + 10*bb.b + 100*cc.c AS numbers FROM (
SELECT 0 a 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) aa
, (SELECT 0 b 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) bb
, (SELECT 0 c 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) cc;
This creates the numbers 0 till 999.
Now you join your table2 with this numbers table in the range of stock. Your final query looks like this:
INSERT INTO table1 (table1.SKU, table1.timestamp_in)
SELECT table2.SKU, "some timestamp" FROM table2
INNER JOIN (
SELECT aa.a + 10*bb.b + 100*cc.c AS n FROM (
SELECT 0 a 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) aa
, (SELECT 0 b 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) bb
, (SELECT 0 c 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) cc
) numbers ON numbers.n BETWEEN 0 AND table2.stock /*assuming you have no negative stock*/
Just make sure, that the numbers table contains more numbers than the highest value in the stock column.

mySQL unique values

I need to get unique values from a table. I have a single column with comma separated keywords. I need to derive a single list of all the keywords without duplicates. Getting the count of how often each keyword is present, too.
From what I have researched, it is an UNPIVOTING like function with an unknown number of columns?
For example:
keywords
red, blue, yellow
blue, orange, black, white
brown, black, clear, pink
blue, violet, orange
Result
color | count
red 1
blue 3
yellow 1
orange 2
black 2
white 1
brown 1
clear 1
pink 1
violet 1
Thank you in advance!!
**
Thus far I have tried adding an explode_table type procedure, but realized I can't call that dynamically from a View. Then I have been experimenting with performing a reverse GROUP_CONCAT() on the column. I haven't been able to produce code that performs.
My version of echo_Me's answer:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(sKeywords, ',', n.n), ',', -1) value , count(*) as counts
FROM tblPatternMetadata 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(sKeywords) - LENGTH(REPLACE(sKeywords, ',', ''))) group by value
Try that:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.keywords, ',', n.n), ',', -1) value , count(*) as counts
FROM table1 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.keywords) - LENGTH(REPLACE(t.keywords, ',', '')))
group by value
DEMO HERE