MySql find maximum item by day for each id - mysql

I have a MySQL table like so:
id | day | item
---------------
1 | 1 | A
1 | 2 | B
1 | 3 | A
2 | 1 | C
2 | 2 | C
2 | 5 | B
3 | 6 | A
3 | 7 | C
I want to get the last item per id by day. So the output would be something like:
id | day | item
---------------
1 | 3 | A
2 | 5 | B
3 | 7 | C
What is the best way to accomplish this?
I know how to do this when the last day is the same for all ids, but I don't know how to do it in the case when each id may have a different last day.

This should work:
select table.* from table
join (select id, max(day) as day from table group by id)
as m on m.id = table.id and m.day = table.day

Related

Get rows with condition on last grouping row

I have table favourite_products with schema like below. I need to count how many people (account_id) like product with id = 12. But the condition is that person marked product as liked on last time.
In this example user with id = 1 marked product 12 as positive for the first time, but then he marked is a non-positive so this value shouldn't be returned. The following example should return 2 rows (for user_id = 5 and user_id = 8). I heard about window function but have mysql in version 5.7 and I can't upgrade it. Do you have some ideas how to write this query?
| id | user_id | product_id | positive |
| 1 | 1 | 12 | 1 |
| 2 | 1 | 12 | 0 |
| 3 | 1 | 15 | 1 |
| 4 | 5 | 12 | 1 |
| 5 | 5 | 12 | 1 |
| 6 | 11 | 18 | 1 |
| 7 | 8 | 12 | 1 |
| 8 | 8 | 12 | 1 |
Following approach should work for all the cases, including the case when a product was disliked and then liked again at the end.
In a Derived table, we can get the maximum id value for every user_id and product_id = 12. This result-set will be joined to the main table appropriately. This will fetch us the complete row (recent activity done by user for a product).
Now, we can consider only those users where the last activity is positive.
Query
SELECT fp.user_id
FROM favourite_products AS fp
JOIN (SELECT user_id,
Max(id) AS max_id
FROM favourite_products
WHERE product_id = 12
GROUP BY user_id) AS dt
ON dt.user_id = fp.user_id
AND dt.max_id = fp.id
AND fp.positive = 1;
Result
| user_id |
| ------- |
| 5 |
| 8 |
View on DB Fiddle

Need help/explanation to JOINED query

I'm kinda lost on what kind of SQL query I should do to achieve what I want.
Let's say I have three tables :
select * FROM trip;
| trip_id | title | description
----------------------------------
| 1 | title1 | desc1 |
| 2 | title2 | desc2 |
| 3 | title3 | desc3 |
| 4 | title4 | desc4 |
| 5 | title5 | desc5 |
| 6 | title6 | desc6 |
select * FROM weekly_report;
| report_id | trip_id| incident_id
----------------------------------
| 1 | 1 | (null) |
| 2 | 1 | (null) |
| 3 | 1 | 1 |
| 4 | 2 | 2 |
| 5 | 3 | 3 |
| 6 | 3 | (null) |
select * FROM incident;
| incident_id | error_code |
----------------------------------
| 1 | 22223 |
| 2 | 25456 |
| 3 | 25456 |
So for a little operationnal knowledge :
The trip table contains 1 record PER trip done by the customer.
The weekly_report contains A report per Week of the trip. (1 trip of 2 weeks will have 2 records, 1 trip or 5 weeks will have 5.. ).
The incident table contains 1 record per incident. (If an incident happened during a week : we create a record in the incident table, else we do nothing)
I'd like to find in a single query (or if it has to be, with subqueries) the number of trips where during at least a week there has been an incident declared for the error_code "25456".
Expected result from the sample data : 2 ( because for trip 2 and three there exist an incident with the error code 25456 ).
I can explain more if needed, is there anybody out there willing to help me ?
Thanks,
You need to take count of distinct trips for related incidents
select count(distinct w.trip_id)
from weekly_report w
inner join incident i
on w.incident_id = i.incident_id
where i.error_code = 25456;
Try this:
SELECT w.trip_id
FROM incident i
INNER JOIN weekly_report w ON i.incident_id=w.incident_id
WHERE error_code='25456'
and if you want the count,then
SELECT COUNT(w.trip_id)
FROM incident i
INNER JOIN weekly_report w ON i.incident_id=w.incident_id
WHERE error_code='25456'

Group by two values

I have the following query:
SELECT
items.*
FROM
`items`
INNER JOIN
`users` ON `items`.`owner` = `users`.`id`
GROUP BY
`items`.`owner`
LIMIT
10
I ensures it is grouped by the user (only one item fetched per user), but I also wish ensure that items with the category, say, "1" only appears once.
But that does not work. Well, query succeeds, but it does not group by category. Multiple categories is still shown. Any ideas?
I have created a SQLFiddle here: http://sqlfiddle.com/#!2/0a4bad/1
Instead of outputting:
+----+----------+-------+
| ID | CATEGORY | OWNER |
+----+----------+-------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 4 |
| 5 | 2 | 5 |
+----+----------+-------+
It should be outputting:
+----+----------+-------+
| ID | CATEGORY | OWNER |
+----+----------+-------+
| 1 | 1 | 1 |
| 4 | 2 | 2 |
| 5 | 2 | 4 |
| 5 | 2 | 5 |
| 8 | 3 | 3 |
+----+----------+-------+
(notice category 1 is only shown ONCE).
I want to ensure that only one item per owner is shown, and then adtionally ensure that a specific category (say 1 and 5) is only shown once. The category 1 and 5 are overpopulated, and if they are not limited, they will be 90% of the output.
You can use DISTINCT to retrieve unique data:
SELECT DISTINCT items.category
select * from items t1
where category not in (1,2)
or not exists (
select 1 from items t2
where t2.id < t1.id
and t2.category = t1.category
)
group by owner
http://sqlfiddle.com/#!2/0a4bad/27

Count downloads with two tables

I have two table and like to know how many downloads a certain name has. Here are my tables
Table "names"
ID | name
==========
1 | foo
2 | bar
3 | zoo
4 | luu
Table "downloads"
ID | name_id | timestamp
=========================
1 | 1 | 1394041682
2 | 4 | 1394041356
3 | 1 | 1394041573
4 | 3 | 1394041981
5 | 1 | 1394041683
Result should be:
ID | name | downloads
=====================
1 | foo | 3
2 | bar | 0
3 | zoo | 1
4 | luu | 1
This should be pretty easy...
It is pretty easy.
Just JOIN tables and COUNT rows. Don't forget to GROUP BY, and COUNT(timestamp) so you could get zero if there isn't any
SELECT n.ID,
n.name,
COUNT(timestamp) as downloads
FROM names n
LEFT JOIN downloads d
ON d.name_id = n.id
GROUP BY n.ID,
n.name
ORDER BY n.ID;
SQL Fiddle

Mysql select row based on multiple rows in same table

I have the following table structure:
item_id | value |
==================
1 | 1 |
1 | 3 |
1 | 4 |
2 | 2 |
2 | 3 |
2 | 4 |
2 | 5 |
3 | 1 |
3 | 5 |
3 | 6 |
4 | 1 |
4 | 3 |
4 | 4 |
4 | 5 |
I have a query that returns those item_id whose value matches with 1, 3 and 4.
So here, the item_ids that should be returned are 1 and 4.
My query:
select item_id from table t
where exists (select item_id from table t1 where value = 1 and t1.item_id = t.item_id)
and exists (select item_id from table t1 where value = 2 and t1.item_id = t.item_id) group by item_id
This query is working fine. Here i am matching only 3 values. What if i want to match 50 such values from the table? (all the 50 values are stored in a php array) The query will be huge and also i want to do the same thing from two different tables in the same query. So, this will double the size of an already huge query. Please suggest me some other way around.
Edited::
table 2
--------
item_id | user_id |
==================
1 | 1 |
1 | 5 |
1 | 7 |
2 | 2 |
2 | 3 |
2 | 4 |
2 | 5 |
3 | 1 |
3 | 5 |
3 | 6 |
4 | 1 |
4 | 3 |
4 | 4 |
4 | 5 |
Now, i want item_id where values from table1 are 1,3,4 and user_id from table2 are 1,5,7
This problem is called Relational Division.
SELECT item_ID
FROM tableName
WHERE value IN (1,3,4)
GROUP BY item_ID
HAVING COUNT(*) = 3
if uniqueness was not enforce on column value for every item_id, DISTINCT is required to count only unique values,
SELECT item_ID
FROM tableName
WHERE value IN (1,3,4)
GROUP BY item_ID
HAVING COUNT(DISTINCT value) = 3
SQLFiddle Demo (both query included)
SQL of Relational Division