Count two or more repeated characters in a string - mysql

I have table like this:
-----------
ID | Value
-----------
1 | AAAA
2 | ABCD
3 | AADC
4 | ABBD
I am trying to figure out how to return the number of times a string occurs in each of the Value.
So, if I want to count of time 'A' and 'B'appears, the sql statement will return like this:
-------------------
ID | Value | Count
-------------------
1 | AAAA | 0
2 | ABCD | 1
3 | AADC | 0
4 | ABBD | 2
5 | ABBB | 3
6 | AABB | 3
7 | AAAB | 3
Is there any way to do this? I do not want to use php, vb, etc. Just MySQL

Seems you want to count the values and then combine the result. I believe something like this will work for you.
SQLFiddle
SELECT
id,
value,
ROUND (
(
LENGTH(value)
- LENGTH(REPLACE(value, "A", ""))
) / LENGTH("A")
) AS count
FROM chars
UNION ALL
SELECT
id,
value,
ROUND (
(
LENGTH(value)
- LENGTH(REPLACE(value, "B", ""))
) / LENGTH("B")
) AS count
FROM chars

You can try this mate:
SELECT
ID,
Value,
LENGTH(REPLACE(Value, 'A', '')) 'count_a',
LENGTH(REPLACE(Value, 'B', '')) 'count_b'
FROM
your_table;
or this one:
SELECT
ID,
Value,
LENGTH(REPLACE(Value, IF(LENGTH(REPLACE(Value, 'A','')) = 3, 'A', 'B'), '')) 'Count',
FROM
your_table;
This one is based on the given expected result

Related

How to get maximum appearance count of number from comma separated number string from multiple rows in MySQL?

My MySQL table having column with comma separated numbers. See below example -
| style_ids |
| ---------- |
| 5,3,10,2,7 |
| 1,5,12,9 |
| 6,3,5,9,4 |
| 8,3,5,7,12 |
| 7,4,9,3,5 |
So my expected result should have top 5 numbers with maximum appearance count in descending order as 5 rows as below -
| number | appearance_count_in_all_rows |
| -------|----------------------------- |
| 5 | 5 |
| 3 | 4 |
| 9 | 3 |
| 7 | 2 |
| 4 | 2 |
Is it possible to get above result by MySQL query ?
As already alluded to in the comments, this is a really bad idea. But here is one way of doing it -
WITH RECURSIVE seq (n) AS (
SELECT 1 UNION ALL SELECT n+1 FROM seq WHERE n < 20
), tbl (style_ids) AS (
SELECT '5,3,10,2,7' UNION ALL
SELECT '1,5,12,9' UNION ALL
SELECT '6,3,5,9,4' UNION ALL
SELECT '8,3,5,7,12' UNION ALL
SELECT '7,4,9,3,5'
)
SELECT seq.n, COUNT(*) appearance_count_in_all_rows
FROM seq
JOIN tbl ON FIND_IN_SET(seq.n, tbl.style_ids)
GROUP BY seq.n
ORDER BY appearance_count_in_all_rows DESC
LIMIT 5;
Just replace the tbl cte with your table.
As already pointed out you should fix the data if possible.
For further details read Is storing a delimited list in a database column really that bad?.
You could use below answer which is well explained here and a working fiddle can be found here.
Try,
select distinct_nr,count(distinct_nr) as appearance_count_in_all_rows
from ( select substring_index(substring_index(style_ids, ',', n), ',', -1) as distinct_nr
from test
join numbers on char_length(style_ids) - char_length(replace(style_ids, ',', '')) >= n - 1
) x
group by distinct_nr
order by appearance_count_in_all_rows desc ;

MySQL display total count of values under limit

I'm pretty new to SQL and am currently trying to run a query which will return the total count of a value under a certain limit (using phpmyadmin).
Say we've got a table like so:
CarID | Car | OwnerID
-------------------
1 | Name | 1
2 | Name | 3
3 | Name | 2
4 | Name | 1
Now I would like to be able to get the total count of cars a owner has if it's under let's say 2 - to then get this:
OwnerID| TotalCars |
---------------------
2 | 1 |
3 | 1 |
How would I accomplish this? My situation is slightly different than the example I gave but it's fundamentally the same exact goal but just different numbers and more records.
When I try, those with more than the number I wish to see return with zero as their value??
(My code)
Code giving me trouble
(My result)
ID 6 has 3 properties so it shouldn't be showing me it at all and I don't understand why it's returning it as 0
You can use GROUP BY COUNT and HAVING
CREATE TABLE Table1
(`CarID` int, `Car` varchar(4), `OwnerID` int)
;
INSERT INTO Table1
(`CarID`, `Car`, `OwnerID`)
VALUES
(1, 'Name', 1),
(2, 'Name', 3),
(3, 'Name', 2),
(4, 'Name', 1)
;
SELECT `OwnerID`, COUNT(*) as countr
FROM Table1
GROUP BY `OwnerID`
HAVING countr < 2
OwnerID | countr
------: | -----:
3 | 1
2 | 1
db<>fiddle here

How to generate a survey curve with SQL query

I have a table with 2 columns WorkItem and LiveDays. For example
| WorkItem | LiveDays |
| A | 8 |
| B | 2 |
| C | 5 |
....
I would like to generate a survey data of the work item. Each item is normalized as starting from day 1 and ending to LiveDays, and value of nth day is how many workitems is still live (in process). For example
| Days | Counter | Comments |
| 1 | 3 | (A, B, C)|
| 2 | 3 | (A, B, C)|
| 3 | 2 | (A, C) |
| 4 | 2 | (A, C) |
| 5 | 2 | (A, C) |
| 6 | 1 | (A) |
| 7 | 1 | (A) |
| 8 | 1 | (A) |
Is it possible to use SQL query instead of inserting data into a new table with transaction?
Thanks
To show it can be done (it does after all answer your original question) here's your example reproduced using Db2 Developer-C 11.1 on dbfiddle.uk: (You did say there were several databases you could use, and this will no doubt serve to illustrate that different databases do things in different ways!). Note: additional MySQL solution further down.
CREATE TABLE surveydata AS (
WITH t1(workitem, livedays)
AS (VALUES ('A', 8), ('B', 2), ('C', 5)),
numbers(seq)
AS (VALUES (1)
UNION ALL
SELECT seq + 1
FROM numbers
WHERE seq < (SELECT MAX(livedays)
FROM t1)),
xdata(workitem, ndays)
AS (SELECT workitem,
seq
FROM t1,
numbers
WHERE seq <= livedays)
SELECT ndays AS "Days",
COUNT(*) AS "Counter",
'(' || LISTAGG(workitem, ', ') WITHIN GROUP (ORDER BY workitem) || ')' AS "Comments"
FROM xdata
GROUP BY ndays
) WITH DATA;
with the result of SELECT * FROM surveydata as below ==>
UPDATE: With a bit more fiddling, I've managed to get a solution using MySQL 8.0 as well:
WITH recursive t1(workitem, livedays)
AS (SELECT 'A', 8
UNION ALL SELECT 'B', 2
UNION ALL SELECT 'C', 5 ),
numbers(seq)
AS (SELECT 1 AS seq
UNION ALL
SELECT seq + 1
FROM numbers
WHERE seq < (SELECT MAX(livedays)
FROM t1)),
xdata(workitem, ndays)
AS (SELECT workitem,
seq
FROM t1,
numbers
WHERE seq <= livedays)
SELECT ndays AS "Days",
COUNT(*) AS "Counter" ,
CONCAT('(', GROUP_CONCAT(workitem ORDER BY workitem SEPARATOR ', '), ')') AS "Comments"
FROM xdata
GROUP BY ndays;

Add row number after splitting a string field

I have a table that contains 2 fields:
ID: text
Suggestions: string (comma separated values)
I would like to make a select query that would return a new numbered rows representing each suggestion with its own number as shown in the original string
Example:
Note: this ranking must be guaranteed to be the same everytime I run the query..
Thanks
If Version of your DB is 8.0+, then with recursive cte as clause might be used as in the following select statement ( after needed DML's provided such as create table and insert statements ):
mysql> create table tab( ID int, suggestions varchar(25));
mysql> insert into tab values(1,'A,B,C');
mysql> insert into tab values(2,'D,E,F,G,H');
mysql> select q2.*,
row_number()
over
(partition by q2.id order by q2.suggestion) as number
from
(
select distinct
id,
substring_index(
substring_index(suggestions, ',', q1.nr),
',',
-1
) as suggestion
from tab
cross join
(with recursive cte as
(
select 1 as nr
union all
select 1+nr from cte where nr<10
)
select * from cte) q1
) q2;
+------+------------+--------+
| id | suggestion | number |
+------+------------+--------+
| 1 | A | 1 |
| 1 | B | 2 |
| 1 | C | 3 |
| 2 | D | 1 |
| 2 | E | 2 |
| 2 | F | 3 |
| 2 | G | 4 |
| 2 | H | 5 |
+------+------------+--------+
Find here same problem is solved.
https://gist.github.com/avoidwork/3749973
I would suggest a series of subqueries:
select id, substring_index(suggestions, ',', 1) as suggestion, 1
from example
where suggestions is not null
union all
select id, substring_index(substring_index(suggestions, ',', 2), ',', -1) as suggestion, 2
from example
where suggestions like '%,%'
union all
select id, substring_index(substring_index(suggestions, ',', 3), ',', -1) as suggestion, 3
from example
where suggestions like '%,%,%'
union all
select id, substring_index(substring_index(suggestions, ',', 4), ',', -1) as suggestion, 4
from example
where suggestions like '%,%,%,%'
union all
select id, substring_index(substring_index(suggestions, ',', 5), ',', -1) as suggestion, 5
from example
where suggestions like '%,%,%,%,%';
This can easily be extended if you have more than 5 options per id.

Join Rows from one huge SQL Table

Many Questions like this are already on stackoverflow but with my min knowledge of SQL i can not put it together.
My table looks like this. I have 1000 Player_Id's and 200 Stat_Id's
PlayerID | StatsID | StatValue
==================================
1 | 1 | 99
1 | 2 | 31
1 | 3 | 1
2 | 1 | 102
2 | 2 | 1
2 | 3 | 33
3 | 1 | 0
3 | 2 | 1
3 | 3 | 3,4
And I would like to get a array of users where one User object looks like this:
{playerId:1, stats:{"1":99, "2":31, "3":1, ...}}
I have tried a lot but nothing is close to what I want to get done. With this SQL i got my best result:
SELECT `PlayerID`,
GROUP_CONCAT(`StatsID` SEPARATOR ', ')
FROM `player_stats`
WHERE 1 group by `PlayerID`
Here is the Result:
Array
(
[0] => Array
(
[PlayerID] => 15895
[stats] => 1, 2, 3
)
[1] => Array
(
[PlayerID] => 21307
[stats] => 1, 2, 3
)
How can I bring the StatValue Columns into my Query?
Would it be better to generate the desired object after the SQL Query or with multiple Queries?
Performance is not very crucial but of course it would be nice if generating the "playerId-array" would not take ages.
Thanks!
You can actually just add the columns to the GROUP_CONCAT():
SELECT `PlayerID`, GROUP_CONCAT(`StatsID`, ':', StatValue SEPARATOR ', ') as stats
FROM `player_stats`
GROUP BY `PlayerID`;
Try
SELECT `PlayerID`, `StatsValues` FROM (
SELECT `PlayerID`, CONCAT(`StatsID`, ',', GROUP_CONCAT(`StatsValues` SEPARATOR ', ')) AS `StatsValues`
FROM tblName
GROUP BY `PlayerID`, `StatsID`);