How to count occurences in comma separated column? - mysql

Question table:
id | tags
--------------------------------------
1 | css,javascript,html
2 | mysql,sql,html
3 | css,spring,php
4 | css,java,html
I am trying to figure out how to return the number of times a string occurs in each of the tags's.
Result Table:
tags | count
--------------------------------------
css | 3
html | 3
javascript | 1
php | 1

You can use:
SqlFiddleDemo
SELECT sub.val AS tags, COUNT(*) AS `count`
FROM
(
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.tags, ',', n.n), ',', -1) AS val
FROM tab 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.tags) - LENGTH(REPLACE(t.tags, ',', '')))
) sub
GROUP BY sub.val

You can simply try like this:
SELECT COUNT(*) FROM my_table WHERE tags like '%css%';
SELECT COUNT(*) FROM my_table WHERE tags like '%html%';
SELECT COUNT(*) FROM my_table WHERE tags like '%javascript%';
SELECT COUNT(*) FROM my_table WHERE tags like '%php%';
One other way is to use it like this:
(LENGTH(`tags`) - LENGTH(REPLACE(`tags`, 'searchword', '')))/LENGTH('searchword')

Related

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 to retrieve multiple data that store inside the same database column?

My database is like
Name | IC | Item
--------------------------
lee | xxx | pear,bear
--------------------------
ron | xxx | apple,dog
what should I do to retrieve the 4 values contained in the column "Item" and then separate them?
Do you have only two items separated by comma in Item? Or it may vary?
LE: you can use this SQL split comma separated row
LLE: just played around with that and this what I've done:
create table myTable(name varchar(7), ic varchar(7), item varchar(200));
insert into myTable(name,ic,item) values ('lee','xxx','pear,bear');
insert into myTable(name,ic,item) values ('ron','xxx','apple,dog');
insert into myTable(name,ic,item) values ('a','xxx','gamma');
insert into myTable(name,ic,item) values ('b','xxx','a,b,c,d');
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.item, ',', n.n), ',', -1) value
FROM myTable 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.item) - LENGTH(REPLACE(t.item, ',', '')))
ORDER BY value;

(i) Create a table from existing one and (ii) display detailed data for which total is stored in table

From a table t1
product_id | quantity | total_amount
I want to create a table t2 with the columns
id | product_id | total_amount/quantity AS product_price
I want each record (t2.product_id, t2.product_price) to be shown t1.quantity times for the respective product:
1 | 400
1 | 400
1 | 400
2 | 75
2 | 75
Could you please tell me, how can I do this using bare SQL?
This seems to create the table, you are looking for:
CREATE TABLE T2 AS
SELECT
#rowid := #rowid + 1 AS id
, product_id
, total_amount / quantity AS product_price
FROM t1, (SELECT #rowid := 0) AS firstID
ORDER BY product_id
;
For the second part of your request, you could try:
SELECT
T.product_id
, T.total_amount / T.quantity AS price
FROM T1 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 <= T.quantity
ORDER BY product_id
;
See it in action: SQL Fiddle.
Please comment if this requires adjustment / further detail.

Merge two colums, multiple rows ignoring duplicates - MySQL

This is, maybe, a stupid question. Not for me: honestly, I'm not so skilled with MySql queries so I'm looking for a little help.
I have a table:
id | type_a | type_b |
__________________________________________________
1 | *color_1*color_2*color_3*| *color_1* |
2 | *color_3* | *color_3*color_2*|
3 | *color_2*color_3* | *color_4* |
4 | *color_1*color_3*color_4*| |
5 | *color_4* | *color_5* |
__________________________________________________
I would like to move "type_b" column content in "type_a" column ignoring duplicate fields (delimited by * and *, ex: color_1. This kind of storage is builded by a Joomla component).
I would like to have this final result:
id | type_a | type_b |
_________________________________________
1 | *color_1*color_2*color_3*| |
2 | *color_3*color_2* | |
3 | *color_2*color_3*color_4*| |
4 | *color_1*color_3*color_4*| |
5 | *color_4*color_5* | |
_________________________________________
What's the best way to accomplish something similar?
Thanks to all!
You could do it with this statement (no, it's not looking nice), assuming the name of your table is example:
UPDATE
example e1
SET
e1.type_a = (
SELECT
CONCAT('*', GROUP_CONCAT(DISTINCT n1.value ORDER BY n1.value SEPARATOR '*'), '*') as type_a
FROM (
SELECT
id,
CASE
WHEN SUBSTRING_INDEX(SUBSTRING_INDEX(TRIM(BOTH '*' FROM e.type_a), '*', n.n), '*', -1) = '' THEN NULL
ELSE SUBSTRING_INDEX(SUBSTRING_INDEX(TRIM(BOTH '*' FROM e.type_a), '*', n.n), '*', -1)
END value
FROM example e CROSS JOIN (
SELECT
a.N + b.N * 10 + 1 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 <= 1 + (LENGTH(e.type_a) - LENGTH(REPLACE(e.type_a, '*', '')))
UNION
SELECT
id,
CASE
WHEN SUBSTRING_INDEX(SUBSTRING_INDEX(TRIM(BOTH '*' FROM e.type_b), '*', n.n), '*', -1) = '' THEN NULL
ELSE SUBSTRING_INDEX(SUBSTRING_INDEX(TRIM(BOTH '*' FROM e.type_b), '*', n.n), '*', -1)
END value
FROM example e CROSS JOIN (
SELECT
a.N + b.N * 10 + 1 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 <= 1 + (LENGTH(e.type_b) - LENGTH(REPLACE(e.type_b, '*', '')))
) n1
WHERE
n1.id = e1.id
GROUP BY
id
),
e1.type_b = ''
;
Demo of the SELECT statement
Explanation
Basically I adapted the method of peterm to get the split done. I had to remove the outer * first by TRIM.
To allow the empty string as column value, I've added the CASE construct, to eliminate such values. If your column has NULL values instead, you could substitute the CASE by
SUBSTRING_INDEX(SUBSTRING_INDEX(TRIM(BOTH '*' FROM e.type_a), '*', n.n), '*', -1)
and
SUBSTRING_INDEX(SUBSTRING_INDEX(TRIM(BOTH '*' FROM e.type_a), '*', n.n), '*', -1)
The UNION (without the ALL keyword) of this construct will give us the list of distinct color values and with GROUP BY id and GROUP_CONCAT we'll get the * separated value list. Last we add a leading and a trailing * to match your requirements.
For the update you've got to modificate the select, so that it returns just one column with one row (with the where clause).
Note
As stated by peterm this will allow up to 100 values in your value list. I don't believe you will need more, but if you will, then you've got to adapt the generating of the numbers up to your needs.

How to use find_in_set for two strings to match in target or anything?

I have following below 2 tables.Here is schema Sqlfiddle for it.
Table 1
Transaction Items
----------- -------------
T1 I1,I3,I7
T2 I7,I2,I3
T3 I1,I2,I3
T4 I2,I3
T5 I2,I3,I4,I5
Table 2
Id Items
------ --------
1 I1,I3
2 I1,I2
3 I2,I4
4 I2,I3
5 I4,I5
I want result in Table 3 like for each record in Table2 like 1st row I1,I3how many time it occurs in Table 1 in each record.It should display in SOT column as answer.Here for 1st one is 2.
Table 3
Id Items SOT
------ ------ --------
1 I1,I3 2
2 I1,I2 1
3 I2,I4 1
4 I2,I3 4
5 I4,I5 1
Can you please advise me for this? I have think of find_in_set but It works for only 1 string to match.
As a demonstration, the following SQL will get you the results you want (I think) with up to 100 comma separated values in Table2.Items.
As you can see it is not pleasant to read, and anyone who comes to maintain this statement in the future would probably be very confused. I would not recommend doing something like this in live code.
SELECT Id, COUNT(*)
FROM
(
SELECT Transaction, anItemCount, ItemVal.Id, COUNT(anItem) AS aCount
FROM
(
SELECT DISTINCT Id, SUBSTRING_INDEX(SUBSTRING_INDEX(Items, ',', AnInt), ',', -1) AS anItem
FROM Table2,
(
SELECT 1 + Units.i + Tens.i * 10 as AnInt
FROM
(SELECT 0 AS i 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) Units,
(SELECT 0 AS i 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) Tens
) Ints
) ItemVal
INNER JOIN
(
SELECT Id, COUNT(DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(Items, ',', AnInt), ',', -1)) AS anItemCount
FROM Table2,
(
SELECT 1 + Units.i + Tens.i * 10 as AnInt
FROM
(SELECT 0 AS i 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) Units,
(SELECT 0 AS i 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) Tens
) Ints
GROUP BY Id
) ItemCnt
ON ItemVal.Id = ItemCnt.Id
INNER JOIN Table1
ON FIND_IN_SET(ItemVal.anItem, Table1.Items)
GROUP BY Transaction, anItemCount, ItemVal.Id
HAVING anItemCount = aCount
) Sub1
GROUP BY Id
If Table2.Items only ever contains 2 values then this could be cut down to:-
SELECT Id, COUNT(*)
FROM
(
SELECT Table1.Transaction, ItemVal.Id, COUNT(anItem) AS aCount
FROM
(
SELECT Id, SUBSTRING_INDEX(Items, ',', 1) AS anItem
FROM Table2
UNION
SELECT Id, SUBSTRING_INDEX(Items, ',', -1) AS anItem
FROM Table2
) ItemVal
INNER JOIN Table1
ON FIND_IN_SET(ItemVal.anItem, Table1.Items)
GROUP BY Table1.Transaction, ItemVal.Id
HAVING aCount = 2
) Sub1
GROUP BY Id;
It could also be done simply when there are only 2 values in Table2.Items with the following:-
SELECT Table2.Id, COUNT(Table1.Transaction) AS aCount
FROM Table2
INNER JOIN Table1
ON FIND_IN_SET(SUBSTRING_INDEX(Table2.Items, ',', 1), Table1.Items)
AND FIND_IN_SET(SUBSTRING_INDEX(Table2.Items, ',', -1), Table1.Items)
GROUP BY Table2.Id
But still hardly pleasant.
SQL Fiddle here:-
http://www.sqlfiddle.com/#!2/03fe9/19