MySQL GROUP by Regex? - mysql

I have the following query
SELECT Count(*) as Total_Count, Col1
FROM Table1
GROUP BY Col1
ORDER BY Total_Count DESC;
I want to zoom in on Col1. The data in Col1 are in the following format:
text-abc1
txt4-abcde22
tex6-abc2
text4-imp4
text-efg1
txt-efg43
I want to be able to group it by
After the first `-`, any first three/four/five characters match
In this example, if we match with first 3 characters. Output will be:
Total_Count Col1
3 abc
1 imp
2 efg
Any other way to achieve this?

You might not need a regex, just string operations. For three characters:
SELECT count(*) AS Total_Count,
SUBSTRING(Col1 FROM POSITION('-' in Col1)+1 FOR 3) AS Col1_zoomed
FROM Table1
GROUP BY Col1_zoomed
ORDER BY Total_Count DESC

select
substring(substring_index(col1,'-',-1),1,3) as grp,
count(*) as total
from table
group by grp

This should do what you want.
SELECT Count(*) as Total_Count, SUBSTRING(Col1, 1, 3)
FROM Table1
GROUP BY SUBSTRING(Col1, 1, 3)
ORDER BY Total_Count DESC;

I wanted to answer the question "MySQL GROUP by Regex?" as the answers here address the problem provided.
You can group by REGEXP with the REGEXP_SUBSTR() function.
REGEXP_SUBSTR(expr, pat[, pos[, occurrence[, match_type]]])
Returns the substring of the string expr that matches the regular
expression specified by the pattern pat, NULL if there is no match. If
expr or pat is NULL, the return value is NULL.
For example:
SELECT
*
FROM
YOUR_TABLE
GROUP BY REGEXP_SUBSTR(YOUR_COLUMN, 'YOUR REGEXP');
Reference: https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-substr

SELECT Count(*) as Total_Count, Col1, REGEXP_SUBSTR(Col1, '[a-z0-9]*', 0, 2) as Col1_combined
FROM Table1
GROUP BY REGEXP_SUBSTR(Col1, '[a-z0-9]*', 0, 2)
ORDER BY Total_Count DESC;
REGEXP_SUBSTR returns the string matching the given regular expression [a-z0-9] starting from position 0 in text and return the 2 occurrence. Documentation for REGEXP_SUBSTR
REGEXP_SUBSTR(<column_name>, <regular_expression>, <starting_position>, <match_occurrence>)

Related

Order by FIELD along with subquery?

I want to order the query results by specific values.
Seems like I can use this:
SELECT
column
FROM
table
ORDER BY
IF(
FIELD(
id,
3,1,2
) = 0,
1,
0
) ASC,
FIELD(
id,
3,1,2
)
My problem is that 3,1,2 comes from another table column. Replacing 3,1,2 with (SELECT column from...) is not working properly. Because the SELECT returns the result as "3,1,2" and not as 3,1,2
I can also extract 3,1,2 one by one, but in this case i get error Subquery returns more than 1 row.
What's the solution here ?
Suppose that the statement that returns the values 3, 1, 2 is something like this:
SELECT somecolumn FROM sometable ORDER BY someothercolumn
then you can use GROUP_CONCAT() to create a comma separated string that contains these values:
SELECT GROUP_CONCAT(somecolumn ORDER BY someothercolumn) col FROM sometable
and then use FIND_IN_SET() instead of FIELD():
SELECT t.column
FROM table t
CROSS JOIN (SELECT GROUP_CONCAT(somecolumn col ORDER BY someothercolumn) FROM sometable) s
ORDER BY
SUBSTRING_INDEX(t.id, s.col) = 0,
SUBSTRING_INDEX(t.id, s.col)
I hope that I understood the logic that you want to apply to sort the table with your ORDER BY clause.

MySQL filter results from a SubSelect using AND or HAVING

I have a query that looks basically like this:
Select t.id,
(
Select GROUP_CONCAT(CONCAT_WS(' ', td.id) SEPARATOR ',') as list
From Table t2
) as id_list // this will add a comma delimited list
From Table t1
Where t1.status IS NULL
And id_list IN (3)
The query result is like this...
id|id_list
--------------------
1 |1
9 |1,3,12,10,15
This does not work as MySQL will not allow me to filter by id_list as an And conditional...
I have also tried this in place of the And conditional, but it does not work also...
Having id_list IN (3)
How can I filter these results based upon the id_list matching some parameter which I set, in this case 3.
I just want to return record id 9, not 1.
Thanks
To check for a value '3' in a comma separated list e.g. '2,3,5' we can use MySQL FIND_IN_SET function.
As a demonstration:
SELECT FIND_IN_SET('3','2,3,5') returns 2
SELECT FIND_IN_SET('3','7,11') returns 0
So for the query in the question, given id_list is a comma separated list, we could do
HAVING FIND_IN_SET('3',id_list)
or equivalently
HAVING FIND_IN_SET('3',id_list) > 0
Note that the IN comparison operator does not work like the FIND_IN_SET function.
The IN is equivalent to equality comparison of individual values. For example,
SELECT 3 IN (2,3,5)
is equivalent to
SELECT 3 = 2 OR 3 = 3 OR 3 = 5
As another example:
SELECT 3 IN ('2,3,5')
is equivalent to
SELECT 3 = '2,3,5'
Just a guess:
SELECT t.id,
(
SELECT GROUP_CONCAT(CONCAT_WS(' ', td.id) SEPARATOR ',') as list
FROM Table t2
) as id_list
FROM Table t1
WHERE t1.status IS NULL
AND FIND_IN_SET(3, id_list) > 0

How to count the total number of results before a hyphen?

I am looking to count the number of results from a SQL count query, the results currently have like 50 results, but in reality there are only 5 results... the results appear in a format such as:
test1-helpme1
test1-helpme3
test1-helpme4
test2-helpme1
test2-helpme2
test3-helpme4
Is there a way I can count just the "testx-" part of the results?
There can be hundreds of results so the number part of "test" can't be hardcoded
SELECT COUNT(*) as CountbyID, OriginalId FROM Table1 GROUP BY OriginalId;
If you want the number of the distinct occurrences of the pattern, then:
SELECT
COUNT(DISTINCT LEFT(OriginalId, INSTR(OriginalId, '-') - 1)) as counter
FROM Table1
or a counter for each one:
SELECT
LEFT(OriginalId, INSTR(OriginalId, '-') - 1) pattern,
COUNT(*) as counter
FROM Table1
GROUP BY LEFT(OriginalId, INSTR(OriginalId, '-') - 1)
Yup you can use LEFT to group by a subset of the string:
declare #test as table (test varchar(100))
insert into #test
Select 'test1-helpme1' UNION ALL
Select 'test1-helpme3' UNION ALL
Select 'test1-helpme4' UNION ALL
Select 'test2-helpme1' UNION ALL
Select 'test2-helpme4'
Select count(*) as countbyID, left(test,5) as originalid from #test group by left(test,5)

MySQL select most occurring or average

I have a MySQL table from which I want to select:
1) Either "most occurring" value, if there is any prevailing
2) Or "average" value, if there is no most occurring value.
Example table 1:
value
1
2
3
4
All values are occurred equally, therefore I want to take AVG(`value`)
Example table 2:
value
1
2
2
3
Value 2 prevails, therefore I want to select the value 2.
What mysql query would do this?
Starting from Gordon's answer I tested and corrected the SQL query in SQL Fiddle:
SELECT IF(t4.numcnts = 1, t1.avgvalue, t2.topvalue) AS result
FROM (select avg(value) as avgvalue from test) t1
CROSS JOIN (select value as topvalue from test group by value order by count(*) desc limit 1) t2
CROSS JOIN join (select count(distinct cnt) as numcnts from
(select count(*) as cnt from test group by value) t3) t4
Here is the Fiddle with the two test tables (switch out test2 for test to see the result when a particular value prevails): http://sqlfiddle.com/#!2/76914/3
My changes were to use an IF instead of a CASEstatement in the SELECTclause and to add the necessary table aliases for the subselects.
The following approach calculates both values and then chooses between them:
select (case when numcnts = 1 then avgvalue else topvalue end)
from (select avg(value) as avgvalue from t) cross join
(select value as topvalue from t group by value order by count(*) desc limit 1) cross join
(select count(distinct cnt) as numcnts from (select count(*) as cnt from t group by value))
Note: if you have ties for the top, but other values as well, then an arbitrary value is returned. You don't specify what to do in this case.
Also, the SQL is untested, so it might have syntax errors.

MySQL Group_Concat Distinct By Id

Is it possible to group_concat records by distinct Ids:
GROUP_CONCAT(Column2 BY DISTINCT Column1)
I need to get the values from column2 by distinct values from column1. Because there are repeating values in column 2, that's why I can't use distinct on column2.
Any thoughts on this? Thanks!
EDIT 1
Sample Table Records:
ID Value
1 A
1 A
2 B
3 B
4 C
4 C
Using the GROUP_CONCAT the I wanted [GROUP_CONCAT(Value BY DISTINCT Id)], I will have an output:
A, B, B, C
EDIT 2
Somehow got my group_concat working:
GROUP_CONCAT(DISTINCT CONCAT(Id, '|', Value))
This will display the concatenated values by distinct id, just need to get rid of the Id somewhere. You can do it without the concat function, but I need the separator. This may not be a good answer but I'll post it anyway.
Try this one, (the simpliest way)
SELECT GROUP_CONCAT(VALUE)
FROM
(
SELECT DISTINCT ID, VALUE
FROM TableName
) a
SQLFiddle Demo
GROUP_CONCAT function support DISTINCT expression.
SELECT id, GROUP_CONCAT(DISTINCT value) FROM table_name GROUP BY id
This should work:
SELECT GROUP_CONCAT(value) FROM (SELECT id, value FROM table GROUP BY id, value) AS d