How to select from database using explode - mysql

I want export data from my SQL database.
Simply use :
SELECT `id`,`tags` FROM `posts`
This query give me those results :
(1, 'handshake,ssl,windows'),
(2, 'office,word,windows'),
(3, 'site')
I want results in this form:
(1, 'handshake'),
(1, 'ssl'),
(1, 'windows'),
(2, 'office'),
(2, 'word'),
(2, 'windows'),
(3, 'site')
How can write a query that give me this results?
Thank you and sorry for my poor English.

If you are using SQL Server
You can apply the fuction
STRING_SPLIT
SELECT id, value
FROM posts
CROSS APPLY STRING_SPLIT(tags, ',')
Check this out:
SQL Fiddle example

After many search and try finally i find the solution:
SELECT
DISTINCT postid , SUBSTRING_INDEX(SUBSTRING_INDEX(tags, ',', n.digit+1), ',', -1) val
FROM
posts
INNER JOIN
(SELECT 0 digit UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6) n
ON LENGTH(REPLACE(tags, ',' , '')) <= LENGTH(tags)-n.digit;

For a max of three words, the code below can be used. If you want more words then you just add more lines. The method may not be fully automated, but it works.
SELECT id, SUBSTRING_INDEX(SUBSTRING_INDEX(tags, ',', 1), ',', -1) FROM tabela
UNION
SELECT id, SUBSTRING_INDEX(SUBSTRING_INDEX(tags, ',', 2), ',', -1) FROM tabela
UNION
SELECT id, SUBSTRING_INDEX(SUBSTRING_INDEX(tags, ',', 3), ',', -1) FROM tabela
ORDER BY id;

Related

How do I insert multiple rows int MySQL where the values of one column are from a single list of values and the others are constant

I'm using MariaDB 10.4. I have a list of values, i.e. one#email.com, two#email.com, and three#email.com (my actual list is much longer).
I would like to make an SQL insert equivalent to the following:
insert into my_table(email, foreign_key_id, timestamp) values
('one#email.com', 1, now()),
('two#email.com', 1, now()),
('three#email.com', 1, now());
While only having to write something like select email from ('one#email.com', 'two#email.com', and 'three#email.com') somewhere in the insert query without duplicating the constants/functions on each line. Can I do this in SQL without any temporary tables?
INSERT INTO my_table (email)
SELECT email
FROM JSON_TABLE( #value,
"$[*]" COLUMNS ( email VARCHAR(32) PATH "$"
)
) AS parse_JSON;
fiddle
Applicable to MySQL 8+
For MariaDB 10.2.3+ use something close to (online fiddle issues incomprehensible errors where there are clearly no errors - so I cannot test)
INSERT INTO my_table (email)
WITH RECURSIVE
cte AS ( SELECT 0 AS num, JSON_VALUE(#json, '$[0]') AS email
UNION
SELECT num + 1, JSON_VALUE(#json, CONCAT('$[', num + 1, ']'))
FROM cte
WHERE JSON_VALUE(#json, CONCAT('$[', num + 1, ']') IS NOT NULL
)
SELECT email
FROM cte;
You can use select:
insert into my_table(email, foreign_key_id, timestamp) values
select e.email, 1, now())
from (select 'one#email.com' as email union all
select 'two#email.com' union all
select 'three#email.com'
) e

How to fix ORDER BY with item ids?

I have a table containing item id's
some examples are:
1
1:3
2:1
2:2
3
3:1
12:2
21:2
I want them to be sorted in the way listed ^
The MYSQL sorts them in following order:
1
1:3
12:2
2:1
2:2
21:2
3
3:1
Anyone has any idea how to fix that problem?
Using SUBSTRING_INDEX() it is possible:
SELECT *
FROM TestTable
ORDER BY CAST(SUBSTRING_INDEX(ColumnVal, ':', 1) AS UNSIGNED),
CAST(SUBSTRING_INDEX(ColumnVal, ':', 2) AS UNSIGNED)
Demo on db<>fiddle
In another way using POSITION()
SELECT *
FROM TestTable
ORDER BY CAST(SUBSTRING_INDEX(ColumnVal, ':', 2) AS UNSIGNED),
POSITION(":" IN ColumnVal),
SUBSTRING(ColumnVal, POSITION(":" IN ColumnVal) + 1, LENGTH(ColumnVal))
Demo on db<>fiddle
SELECT _table.*
# , RPAD(SUBSTRING_INDEX(_table._col, ':', 1), 3, 0)
FROM
(
SELECT
CAST('1' AS CHAR) AS _col
UNION
SELECT
'1:3'
UNION
SELECT
'2:1'
UNION
SELECT
'2:2'
UNION
SELECT
'3'
UNION
SELECT
'3:1'
UNION
SELECT
'12:2'
UNION
SELECT
'21:2') _table
ORDER BY RPAD(SUBSTRING_INDEX(_table._col, ':', 1), 3, 0),
RPAD(SUBSTRING_INDEX(_table._col, ':', 2), 5, 0)
;
You may use ABS() or CAST() if that satisfy you as the following:
SELECT * FROM table ORDER BY ABS(column);
SELECT * FROM table ORDER BY CAST(column as DECIMAL);

SQL query with subquery

My data is like this:
data1_qqq_no_abc_ccc
data1_qqq_abc_ccc
data2_qqq_no_abc_ccc
data2_qqq_abc_ccc
data3_qqq_no_abc_ccc
data4_qqq_no_abc_ccc
data4_qqq_abc_ccc
...
Now I want to get the fields where data has substring _no_abc_ccc, but doesn't have _abc_ccc. In the above example, its data3
I am trying to create a query for it.
rough one is
select SUBSTRING_INDEX(name, 'abc', 1)
from table1
where SUBSTRING_INDEX(name, 'abc', 1) not LIKE "%no"
and NOT IN (select SUBSTRING_INDEX(name, '_no_abc', 1)
from table
where name LIKE "%no_abc");
Something like this (?)
create table t (
col text
);
insert into t
values
('data1_qqq_no_abc_ccc'),
('data1_qqq_abc_ccc'),
('data2_qqq_no_abc_ccc'),
('data2_qqq_abc_ccc'),
('data3_qqq_no_abc_ccc'),
('data4_qqq_no_abc_ccc'),
('data4_qqq_abc_ccc');
select f from (
select SUBSTRING_INDEX(col, '_', 1) as f, SUBSTRING_INDEX(col, '_', -3) as s from t
) tt
group by f
having
count(case when s = 'no_abc_ccc' then 1 end) > 0
and
count(case when s like '%qqq_abc%' then 1 end) = 0
demo

Get Values not in the second table using find_in_set

I have two tables and i need to get list of all store_ids that are not in the other table
BusinessUnit Table User Table
StoreId(varchar) StoreId(varchar)
1 1,2
2 3,4
3 1,5
4 4,6
7 4
How to get values of storeid 5,6 which are not present in the business unit table but are present in the user Table? Tried to use several using find_in_set and nothing works.
Use SUBSTRING_INDEX to get all the values from the CSV field. Since there can be up to 6 IDs in the CSV, you need to call it once for each position.
SELECT u.StoreId
FROM (
select substring_index(StoreId, ',', 1) AS StoreID
FROM User
UNION
select substring_index(substring_index(StoreId, ',', 2), ',', -1)
FROM User
UNION
select substring_index(substring_index(StoreId, ',', 3), ',', -1)
FROM User
UNION
select substring_index(substring_index(StoreId, ',', 4), ',', -1)
FROM User
UNION
select substring_index(substring_index(StoreId, ',', 5), ',', -1)
FROM User
UNION
select substring_index(substring_index(StoreId, ',', 6), ',', -1)
FROM User) AS u
LEFT JOIN BusinessUnit AS b ON u.StoreId = b.StoreID
WHERE b.StoreId IS NULL
DEMO
IF you know all the possible values (and the number of them is reasonably manageable) you can populate a new table with them (you can make it TEMPORARY or just DROP it afterwards), and do this
SELECT *
FROM (
SELECT allIDs.Id
FROM allIDs
INNER JOIN `User` AS u
-- ON CONCAT(',', u.StoreID, ',') LIKE CONCAT('%,', allIDs.Id, ',%')
ON FIND_IN_SET(allIDs.Id, u.StoreID)
) AS IDsInUserTable
LEFT JOIN `BusinessUnit` AS b ON IDsInUserTable.Id = b.StoreID
HAVING b.StoreID IS NULL
;
In this example, allIDs is the aforementioned "possible values" table.

mysql select substrings and group them by column

I am trying to divide data in one onf the tables on my MySQL database.
Column contains data like this:
de:"Sweatjacke*";en:"jacket*";pl:"bluza*";
de:"*";en:"*";pl:"bluza*";
fr:"*";de:"*";en:"*";pl:"dres junior*";cz:"*";
pl:"bluza";
And I am trying to divide all of the translations into separate columns. Already came with solution to do this by using:
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 1), ';', -1) as tr1,
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 2), ';', -1) as tr2,
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 3), ';', -1) as tr3,
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 4), ';', -1) as tr4,
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 5), ';', -1) as tr5
FROM product;
statement, but that results in:
tr1 tr2 tr3 tr4 tr5
fr:"*" de:"*" en:"*" pl:"bluza*" cz:"*"
fr:"*" de:"Sweatjacke*" en:"jacket*" pl:"bluza*" cz:"*"
de:"Sweatjacke*" en:"jacket*" pl:"bluza*"
And I want to have the results gruped by translation type (pl/de/en) so in each collumn one type of translatoin is present. For example in column1 = pl:, column2 = en: etc.
Any one came across similar problem and knows a way to solve it?
You need to unpivot the data, then select the first and second part of each value and then re-aggregate it.
However, a better form for the data is really to have language/translation. The following produces this:
select substring_index(tr, ':', 1) as l, substring_index(tr, ':', 2) as t, name
from (select SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', n.n), ';', -1) as tr, n, name
from product p cross join
(select 1 as n union all select 2 union all select 3 union all select 4 union all
select 5
) n
) n
You would probably want an "id" column or "word" column to identify each row, rather than the name column.
You can now pivot this result to get what you want:
select max(case when l = 'en' then name end) as en,
max(case when l = 'fr' then name end) as fr,
max(case when l = 'de' then name end) as de,
max(case when l = 'pl' then name end) as pl,
max(case when l = 'cz' then name end) as cz
from (select substring_index(tr, ':', 1) as l, substring_index(tr, ':', 2) as t, name
from (select SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', n.n), ';', -1) as tr, n, name
from product p cross join
(select 1 as n union all select 2 union all select 3 union all select 4 union all
select 5
) n
) n
) lt
group by name;
Managed to solve it by using some of the string related functions funcitons:
SELECT
SUBSTRING_INDEX( SUBSTRING( name, LOCATE( "pl:", name ) , 150 ) , ';', 1 ) AS pl,
SUBSTRING_INDEX( SUBSTRING( name, LOCATE( "en:", name ) , 150 ) , ';', 1 ) AS en,
SUBSTRING_INDEX( SUBSTRING( name, LOCATE( "de:", name ) , 150 ) , ';', 1 ) AS de,
SUBSTRING_INDEX( SUBSTRING( name, LOCATE( "fr:", name ) , 150 ) , ';', 1 ) AS fr
FROM product
Thanks to everyone for help.
As far as I understand you want to UNPIVOT your data. There is no such function in MySQL, so you might want to export your data into MSSQL (you can use free MSSQL Express) and use UNPIVOT function: http://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx