mySQL select latest distinct rows from table [duplicate] - mysql

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)

Related

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 |

Group only if there are rows to be grouped

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 |

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

count value for each unique id

I have a table
id value
1 a
2 a
3 b
4 b
5 b
6 c
My id is primary.
I have total 2 a , 3 b and 1 c. So I want to count total repeat value in each primary id which matches on it
I want this format
id value_count
1 2
2 2
3 3
4 3
5 3
6 1
Try this query:
SELECT a.id, b.valueCnt
FROM tableA a
INNER JOIN (SELECT a.value, COUNT(a.value) valueCnt
FROM tableA a GROUP BY a.value) AS B ON a.value = b.value;
Check the SQL FIDDLE DEMO
OUTPUT
| ID | VALUECNT |
|----|----------|
| 1 | 2 |
| 2 | 2 |
| 3 | 3 |
| 4 | 3 |
| 5 | 3 |
| 6 | 1 |
Try This
select id, value_count from tablename as a1
join (select count(*) as value_count, value from tablename group by value) as a2
on a1.value= a2.value
I suggest you use a subselect without any joins:
SELECT
a.id,(SELECT COUNT(*) FROM tableA WHERE value = a.value) as valueCnt
FROM tableA a
Fiddle Demo
You need to use subquery.
SELECT table.id , x.value_count
FROM table
INNER JOIN
(SELECT t1.value, count(t1.id) as value_count
FROM table t1
Group by t1.value
) x on x.value = table.value

Why is this two table into one table union, where showing invalid result in MySQL?

I have a table1 (records 3), and table2 (records 3).
Where i have field name in both.
Now i want to make a result from those two table
which will show me both table records and take only one if there is duplicate.
from that result i will do main query using like or or other logical statements
So my expected output records will contain 5 rows not 6 rows. How do i do that?
Example:
table1: table2:
+-------------------------+ +--------------------------------+
| Name | ID | Name | ID
+-------------------------- +---------------------------------
| A | 1 | 1 December Name | 4
| B | 2 | D | 5
| 1 December Name | 3 | E | 6
My Expected output is following which works, but does not work when i use WHERE
like to only get '1 December Name':
+-----------------------------------------------------+
| Name | ID
+-----------------------------------------------------
| A | 1 table1
| B | 2 table1
| 1 December Name | 3 table2 or table1 (no unique)
| D | 4 table2
| E | 5 table2
I tried this:
SELECT * FROM
(
(
SELECT name AS name FROM table1
)
UNION
(
SELECT anothername AS name FROM table2
)
) as t
WHERE name like '%1 December Name%'
limit 1,10
Output: Your SQL query has been executed successfully ( Query took 0.2798 sec )
Problem: The following query has no error but it does not find that record which contain '1 December Name'
Follow up: works i know now which ID it used
SELECT NAME, ID, STATUS FROM
(
(
SELECT NAME AS name , id, CONCAT('table1') AS STATUS FROM table1
)
UNION ALL
(
SELECT ANOTHERNAME AS name, id, CONCAT( 'table2' ) AS STATUS FROM table2
)
) AS t
WHERE
t.NAME LIKE '%1 December Name%'
LIMIT 1 , 10;
You can get something similar to what you want:
select name, group_concat(id) from
(select name, 'table1' as id from table1
union all
select name, 'table2' from table2) x
group by name
Output would be:
+------------------------------------+
| Name | ID
--------------------------------------
| A | table1
| B | table1
| 1 December Name | table1,table2
| D | table2
| E | table2
UNION ALL is the right choice (not UNION), because it does not remove duplicates, and preserves row order
Try this
(SELECT name FROM table1 )
UNION (SELECT name FROM table2);