SELECT all the newest records distinct - mysql

i have table structure like this
sn | person_id | image_name |
1 | 1 | abc1.jpb
2 | 1 | aa11.jpg
3 | 11 | dsv.jpg
4 | 11 | dssd.jpg
5 | 11 | sdf.jpg
I need distinct person_id newest row as following
2 | 1 | aa11.jjpb
5 | 11 | sdf.jpg
IT is possible ?

SELECT * FROM yourtable GROUP BY person_id ORDER BY sn DESC
Essentially you want to select all records from your table. Then it is grouped by the person_id (limiting the result to 1 per person id)... Ordering by SN decending means that it will return the most recent (highest) sn
Update: (and verified)
SELECT * FROM (SELECT * FROM stackoverflow ORDER BY sn DESC) a GROUP BY person_id ORDER BY sn

SELECT * FROM table GROUP BY person_id HAVING MAX(sn)
EDIT
SELECT f.*
FROM (
SELECT person_id, MAX(sn) as maxval
FROM table GROUP BY person_id
) AS x INNER JOIN table AS f
ON f.person_id = x.person_id AND f.sn = x.maxval;
where table is your table name.

SELECT * FROM table a WHERE a.`id` = ( SELECT MAX(`id`) FROM table b WHERE b.`person_id` = a.`person_id` );
What you are doing inside the parenthesis is selecting the max id for the rows that have that distinct person_id. So for each unique person_id you are getting the most recent entry.

Related

Mysql INNER JOIN sub table with comma separated values from main table column

I want to join the last inserted comma separated values from daily_discounts.discount_product table limit 1 in the products table. Its possible to achieve this in one query ?
Tried :
SELECT * FROM `daily_discounts` INNER JOIN products WHERE FIND_IN_SET(products.product_id , daily_discounts.discount_products)
SELECT * FROM `daily_discounts` INNER JOIN products ON FIND_IN_SET(products.product_id , daily_discounts.discount_products) LIMIT 1
Table daily_discounts:
+-------------+---------------------+
| discount_id | discount_products |
+-------------+---------------------+
| 1 | 960,310,165,702 |
+-------------+---------------------+
| 2 | 231,822,379,420 |
+-------------+---------------------+
| 3 | 518,56,803,858 |
+-------------+---------------------+
Table products result wanted :
+------------+--------------------+
| product_id | product_sale_price |
+------------+--------------------+
| 518 | 10.25 |
+------------+--------------------+
| 56 | 11.24 |
+------------+--------------------+
| 803 | 5.55 |
+------------+--------------------+
| 858 | 13.52 |
+------------+--------------------+
I'm using two queries in order to work
First I select the last inserted record on daily_discounts table:
select `discount_products` from `daily_discounts` order by `discount_id` desc limit 1
Second I Select the Products table
select `product_id`, `product_sale_price from `products` where `product_id` in (518, 56, 803, 858) order by `product_id` desc)
You can try using row_number()
select * from
(
SELECT *,row_number() over(order by discount_id desc) as rn
FROM `daily_discounts`
)A
INNER JOIN products WHERE FIND_IN_SET(products.product_id,A.discount_products) and rn=1
if "latest" row is the one with the highest value value of discount_id, assuming discount_id is a unique identifier (or primary key)
SELECT p.product_id
, p.product_sale_price
FROM ( -- inline view to get identifier of latest row
SELECT MAX(l.discount_id) AS latest_discount_id
FROM `daily_discounts` l
) m
JOIN `daily_discounts` d
ON d.discount_id = m.latest_discount_id
JOIN `products` p
ON FIND_IN_SET(p.id,d.discount_products)
ORDER
BY FIND_IN_SET(p.id,d.discount_products)
if there's some other column or expresssion we need to order the rows by, in order to determine which row(s) qualify and which of those is the latest, we could modify the inline view query
SELECT p.product_id
, p.product_sale_price
FROM ( -- inline view to get identifier of latest row
SELECT l.discount_id AS latest_discount_id
FROM `daily_discounts` l
WHERE ...
ORDER BY ...
LIMIT 1
) m
JOIN `daily_discounts` d
ON d.discount_id = m.latest_discount_id
JOIN `products` p
ON FIND_IN_SET(p.id,d.discount_products)
ORDER
BY FIND_IN_SET(p.id,d.discount_products)

How to delete old duplicate rows based on 2 columns but keep the latest row?

So I have this table (called test_table)
id | hotel_id | user_id
1 | 1 | 1
2 | 1 | 1
3 | 1 | 2
4 | 2 | 3
5 | 1 | 2
6 | 3 | 3
So if the hotel_id and the user_id is the same, then I want to delete the duplicate rows but keep the latest row (the latest row is the row with the higher id).
So after deleting my table would look like the table below.
I deleted id 1 because there is a newer row id 2.
I deleted id 3 because there is a newer row id 5.
id | hotel_id | user_id
2 | 1 | 1
4 | 2 | 3
5 | 1 | 2
6 | 3 | 3
I tried with the code below but it only checks if one column is a duplicate. What is the most efficient way to do this?
delete test_table
from test_table
inner join (
select max(id) as lastId, hotel_id
from test_table
group by hotel_id
having count(*) > 1) duplic on duplic.hotel_id = test_table.hotel_id
where test_table.id < duplic.lastId;
The traditional way in MySQL uses a JOIN:
delete tt
from test_table tt join
(select tt.hotel_id, tt.user_id, max(tt.id) as max_id
from test_table tt
group by tt.hotel_id, tt.user_id
) tokeep
on tokeep.hotel_id = tt.hotel_id and
tokeep.user_id = tt.user_id and
tokeep.max_id > tt.id;
If id is unique in the table, this can be simplified to:
delete tt
from test_table tt left join
(select tt.hotel_id, tt.user_id, max(tt.id) as max_id
from test_table tt
group by tt.hotel_id, tt.user_id
) tokeep
on tt.id = tokeep.max_id
where to_keep.max_id is null;
In MySQL 8.x (available since April 2018) you can use windows functions to identify the obsolete rows. For example:
delete from test_table where id in (
select id
from (
select
id, row_number() over(partition by hotel_id, user_id order by id desc) as rn
from test_table
) x
where rn <> 1
)

Mysql Query to find the last transaction date with the purchased item from Purchase_history table

Table: purchase_history having all details of users
Fields are : id,uid, purchase_date, item_id, item_size, item_color
where id is a primary key.
There are many rows for an similar uid. e.g.
id | uid | purchase_date | item_id | item_size | item_color
1 | 200 | 2016-10-22 | 1021 | 3 | red
2 | 122 | 2016-08-02 | 21 | 1 | black
3 | 200 | 2016-05-01 | 222 | 1 | blue
4 | 101 | 2016-01-07 | 102 | 1 | red
So now I want a single query to get the last transaction date, item_id and uid group by uid. I used below query:
select uid, max(purchase_date), item_id from purchase_history group by uid;
it gives me correct uid and purchase date but the item id is not picked from the last row. It is coming from the first row. Is there any way that we can find the item id from the last row with uid and purchase_date?
Try this:
select uid, max(purchase_date) as date, item_id from purchase_history group by uid ORDER by date desc,item_id desc
Make sure that you item_id type is an integer.
You can find max of purchase date for each user in a subquery and join it with the main table like so:
select t1.uid, t1.purchase_date, t1.item_id
from purchase_history t1
inner join (
select uid, max(purchase_date) purchase_date
from purchase_history
group by uid
) t2 on t1.uid = t2.uid
and t1.purchase_date = t2.purchase_date;
NOTE: It'll give multiple rows for a uid, if there are rows with multiple max dates.
Use correlated subquery:
SELECT uid, purchase_date, item_id
FROM purchase_history p1
WHERE purchase_date = (
SELECT MAX(purchase_date)
FROM purchase_history p2
WHERE p2.uid = p1.uid
);
try this query
select * from (select * from purchase_history order by purchase_date asc) purchase_history group by uid;

MySQL, understanding SQL query behavior

I have a simple MySQL table:
| id | sid | date |
+--------+---------+------------+
| 1 | 1 | 2013-12-01 |
+--------+---------+------------+
| 3 | 2 | 2013-12-17 |
+--------+---------+------------+
| 4 | 1 | 2013-12-17 |
+--------+---------+------------+
| 5 | 1 | 2013-12-18 |
+--------+---------+------------+
I need group this table by sid field and get records with max id for each sid with correct date. I try below code:
SELECT MAX(id), date FROM my_table GROUP BY sid
But the date field is incorrect, for example I get date 2013-12-01 with id 5 as a result.
What am I doing wrong ?
The way standard SQL is defined (at least up to ansi 1992, others will correct me), any field of your SELECT clause must be included in your group by condition. [Mysql allows you to not do so, but that is why it is confusing: the results are not as you expect]
Your query should then be:
SELECT MAX(id), date FROM my_table GROUP BY sid, date
But in this case, clearly this is not what you want. Your requirement is to get the date corresponding to the MAX(id) for each sId.
You have to isolate each part of the algorithm in different queries.
1 - get the max id for each sid:
SELECT MAX(id) AS id, sid FROM my_table GROUP BY sid
2 - get the date corresponding to the max of ids for each sid:
SELECT date FROM my_table WHERE sid = X AND id = Y
3 - join these 2 queries using an INNER JOIN or more shortly, a JOIN:
SELECT m.sid, m.id, m.date
FROM my_table m
JOIN (SELECT MAX(id) AS id, sid FROM my_table GROUP BY sid) t
ON t.sid = m.sid AND m.id = t.id
You need a join:
SELECT a.id, a.date
FROM foo a
INNER JOIN (SELECT MAX(id) as max_id FROM foo GROUP BY sid) b ON a.id = b.max_id

Group by in MySQL

I have a table of the following structure:
ID | COMPANY_ID | VERSION | TEXT
---------------------------------
1 | 1 | 1 | hello
2 | 1 | 2 | world
3 | 2 | 1 | foo
is there a way to get the most recent version of records only, i.e. I would want to have as a result set the IDs 2 and 3?
I'm sure there are better ways, but I tend to use this kind of query:
SELECT *
FROM
(SELECT * FROM test ORDER BY VERSION DESC) AS my_table
GROUP BY COMPANY_ID
Produces this result set:
ID | COMPANY_ID | VERSION | TEXT
---------------------------------
2 | 1 | 2 | world
3 | 2 | 1 | foo
Try this:
SELECT *
FROM (
SELECT company_id, MAX(version) maxVersion
FROM table
GROUP BY company_id ) as val
JOIN table t ON (val.company_id = t.company_id AND t.version = val.maxversion)
If your IDs are ordered (newer version iff higher id):
SELECT t.*, a.maxversion
FROM (
SELECT MAX(id) maxid, MAX(version) maxversion
FROM table
GROUP BY company_id
) a
INNER JOIN table t
ON a.maxid = t.id
However, if your IDs are not properly ordered, you need to use the following query:
SELECT t.*
FROM (
SELECT company_id, MAX(version) maxversion
FROM table
GROUP BY company_id
) v
INNER JOIN table t
ON v.company_id = t.company_id
AND v.maxversion = t.version
(assuming there's an UNIQUE constraint/index on (company_id, version))