Group only if there are rows to be grouped - mysql

I would like your assistance in solving an issue which I am battling now for days without even coming close to a solution. Unfortunately, I have already posted my issue and was not able to make any improvement with the suggestion delivered.
What I would like to achieve is somewhat attained by GROUP BY and HAVING with the possibility of CASE WHEN but whatever I do I am not getting to what I desire.
What I want to achieve is a GROUP BY only when the contents of the group exceed 3 rows and leave the individual items i.e. not grouped when group is less than or equal to three.
EXAMPLE
ID DESC VAL1 VAL 2 VAL 3
1 DESC1 2 2 4
2 DESC2 2 2 4
3 DESC3 2 2 4
4 DESC4 2 2 4
5 DESC5 1 1 2
6 DESC6 1 1 2
GROUP BY will be through VAL1, VAL2, VAL 3 through the following
SELECT * FROM TABLE1 GROUP BY VAL1,VAL2,VAL3
This will yield the following:
ID DESC VAL1 VAL 2 VAL 3
1 DESC1 2 2 4
5 DESC5 1 1 2
However what I need is the following:
ID DESC VAL1 VAL 2 VAL 3
1 DESC1 2 2 4
5 DESC5 1 1 2
6 DESC6 1 1 2
Can this be achieved with GROUP BY, what I think of is subquery but I cannot manage. Your assistance will be very much appreciated.
DBMS is MySQL.

Try this one. It might require some minor tweaks, as I didn't test it. But i think you will get the idea.
Select *
from table1
where md5(concat(val1,val2,val3)) in (
SELECT md5(concat(val1,val2,val3))
FROM TABLE1
GROUP BY VAL1,VAL2,VAL3
having count(*) > 3)
group by VAL1,VAL2,VAL3
union
Select *
from table1
where md5(concat(val1,val2,val3)) not in (
SELECT md5(concat(val1,val2,val3))
FROM TABLE1
GROUP BY VAL1,VAL2,VAL3
having count(*) > 3)

With UNION ALL, for the 2 different cases:
select t.* from tablename t inner join (
select min(id) minid
from tablename
group by val1, val2, val3
having count(*) > 3
) g on g.minid = t.id
union all
select * from tablename t
where (
select count(*) from tablename
where val1 = t.val1 and val2 = t.val2 and val3 = t.val3
) <= 3
See the demo

If you are using MySQL 8.0, you can achieve this simply with window functions COUNT() and ROW_NUMBER():
SELECT id, descr, val1, val2, val3
FROM (
SELECT
t.*,
COUNT(*) OVER(PARTITION BY val1, val2, val3) cnt,
ROW_NUMBER() OVER(PARTITION BY val1, val2, val3 ORDER BY id) rn
FROM mytable t
) x WHERE cnt < 3 OR rn = 1
ORDER BY id
In the inner query, cnt indicates how many records have the same val1, va2, val3 as the current one. rn assigns a rank to each record within groups of records having the same val1, va2, val3. The outer query then uses these two pieces of information to filter the relevant records.
Demo on DB Fiddle:
| id | descr | val1 | val2 | val3 |
| --- | ----- | ---- | ---- | ---- |
| 1 | DESC1 | 2 | 2 | 4 |
| 5 | DESC5 | 1 | 1 | 2 |
| 6 | DESC6 | 1 | 1 | 2 |

Related

Is there way to limit number of rows for each element in a IN clause? [duplicate]

This question already has an answer here:
Set limit for IN condition element that evaluate true
(1 answer)
Closed 1 year ago.
I am trying to write a query that looks like this:
Select * from table1 where field1 = 4 and field2 in (2,3,4,5);
Let's say I want 25 rows for each element in my field2 list (100 rows all together), how can I achieve this?
If you add a ROW_NUMBER to your query with field2 as Ppartition, you can select the number of rows you need per field.
you have to add a ORDER BY to the window function tio get the correct rows, but i don't know enough about your table
SELECT *
FROM
(Select *, ROW_NUMBER() OVER(PARTITION BY fild2 ) rn from table1 where field1 = 4 and field2 in (2,3,4,5)) t2
WHERE rn <= 4
and here is a version for mysql 5.7
CREATE TABLE table1 ( field1 int ,field2 int)
INSERT INTO table1 VALUES(4,2),(4,2),(4,2),(4,2),(4,2),(4,3),(4,3),(4,3),(4,3),(4,4)
SELECT * FROM
(SELECT
field1,
IF (#field2 = field2 ,#row_number := #row_number + 1,#row_number := 1) AS rn,
#field2 := field2 field2
FROM
(SELECT * FROM table1 where field1 = 4 and field2 in (2,3,4,5) ORDER BY field2) t1,
(SELECT #field2:=0,#row_number:=0) as t ) t2
WHERE rn <= 4
field1 | rn | field2
-----: | -: | -----:
4 | 1 | 2
4 | 2 | 2
4 | 3 | 2
4 | 4 | 2
4 | 1 | 3
4 | 2 | 3
4 | 3 | 3
4 | 4 | 3
4 | 1 | 4
db<>fiddle here
If you are concern by this, you are having an architecture problem. The limit exists but you have to avoid it even the half, in any case the wrong consumptions of your own resources.
Several solutions to this, but the normal situation is make a temporal (USP) or definitive transactional table, put the data in them, select/join the data and drop temporal table / truncate definitive table, after use.

Displaying records where the same value have been mentioned more than 3 times in SQL

How can I find a value that has been mentioned several times in a row.
ID |1_Jan|3_Jan|4_Jan|4_Jan|
12 | 2 | 3 | 2 | 4 |
31 | 3 | 4 | 3 | 1 |
25 | 1 | 1 | 1 | 1 |
26 | 3 | 3 | 3 | 3 |
In the case of this table, I want to get out ID 25 and 26 because here the values 1 and 3 have been used 3 or more times in a record.
I was also wondering how can I for example only get out ID 25 even if 26 also has 3 or more?
You can select the rows with all equal column values, and then order by common column value:
with cte as (select t.id, t.1_Jan r, (t.1_Jan = t.2_Jan) and (t.2_Jan = t.3_Jan) and (t.3_Jan = t.4_Jan) val from test_table t)
select c.id from cte c where c.val = 1 order by c.r limit 1;
Output:
id
25
See demo.
This answers the original version of the question.
One way is to unpivot and aggregate:
select id, val, count(*)
from ((select id, 1_jan as val from t) union all
(select id, 2_jan as val from t) union all
(select id, 3_jan as val from t) union all
(select id, 4_jan as val from t)
) t
group by id, val
having count(*) >= 3;

How can I create a column with incremented values from a column with cumulated values in MySQL?

Table1 contains a column with cumulated values (all positive integers):
id ValuesCum
1 5
2 8
3 20
I would like to write a statement that returns an extra column with the incremented values for each row. The output should read something like:
id ValuesCum ValuesInc
1 5 (5)
2 8 3
3 20 12
Does anyone have a solution for this?
If you are running MySQL 8.0, you can use window function lag() for this:
select
t.*,
ValuesCum - lag(ValuesCum, 1, 0) over(order by id) ValuesInc
from mytable t
In earlier versions, an alternative is a correlated subquery:
select
t.*,
ValuesCum - (
select coalesce(max(t1.ValuesCum), 0)
from mytable t1
where t1.id < t.id
) ValuesInc
from mytable t
You can use a correlated subquery to get the value of ValuesCum of the previous id:
select t.*,
t.ValuesCum -
coalesce((select ValuesCum from tablename where id < t.id order by id desc limit 1), 0) ValuesInc
from tablename t
See the demo.
Results:
| id | ValuesCum | ValuesInc |
| --- | --------- | --------- |
| 1 | 5 | 5 |
| 2 | 8 | 3 |
| 3 | 20 | 12 |

mySQL select latest distinct rows from table [duplicate]

This question already has answers here:
Retrieving the last record in each group - MySQL
(33 answers)
Closed 2 years ago.
I have this table.
id country col1 col2 col3
1 country1 1 2 3
2 country1 2 2 1
3 country1 1 3 2
4 country2 3 2 2
5 country2 3 3 3
6 country3 3 2 2
7 country3 3 1 1
I am trying to output the last row of each distinct country.
id country col1 col2 col3
3 country1 1 3 2
5 country2 3 3 3
7 country3 3 1 1
I have tried various solutions such as:
select distinct(country), col1, col2, col3 from ( SELECT country, col1, col2, col3 from tablename order by id DESC) a limit 1
However, I cannot get the required output.
How can I obtain the latest distinct row for each country?
Thank you!
You can filter with a correlated subquery:
select t.*
from mytable t
where t.id = (select max(t1.id) from mytable t1 where t1.country = t.country)
It's simple to get all the last ids with this query:
select max(id) from tablename group by country
and use it to return the rows that you want:
select * from tablename
where id in (select max(id) from tablename group by country)
or with not exists:
select t.* from tablename t
where not exists (
select 1 from tablename
where country = t.country and id > t.id
);
See the demo.
Results:
> id | country | col1 | col2 | col3
> -: | :------- | ---: | ---: | ---:
> 3 | country1 | 1 | 3 | 2
> 5 | country2 | 3 | 3 | 3
> 7 | country3 | 3 | 1 | 1
Select all the elements in the table and in the WHERE condition filter by a in subquery, in that subquery just group by country:
SELECT *
FROM tablename
WHERE id IN (SELECT MAX(id) FROM tablename GROUP BY country)

how to count how many times a number is repeated and more than one column

example::
JOHN | 1 | 6 | 2
PETER | 1 | 7 | 6
MARK | 2 | 1 | 6
DIANNA | 3 | 2 | 1
SPIDERMAN | 4 | 1 | 6
JAMIE FOXX | 5 | 1 | 6
how can I do a select count how many times that the numbers are repeated in each of the 3 columns
Example:
number 1 is repeated 6 times.
the number 6 is repeated 5 times.
Assuming your number column are c1,c2 and c3 and the table is t.
select c,count(*)
from ( select c1 as c from t
union all select c2 from t
union all select c3 from t
) t
group by c
;
Assuming you are looking for 1
A way is using union and sum
select sum(num) from
(
select count(*) as num
from my_table
where col1 = 1
union all
select count(*)
from my_table
where col2 = 1
union all
select count(*)
from my_table
where col3 = 1
) t
SELECT COUNT(CASE WHEN col1 = #number THEN 1 END) +
COUNT(CASE WHEN col2 = #number THEN 1 END) +
COUNT(CASE WHEN col3 = #number THEN 1 END) as repeat
FROM YourTable, (SELECT #number := 1) as parameter