Apply WHERE after GROUP BY - mysql

I have a table with items that are part of a thread, so they have a thread ID, each item also has a date (UNIX timestamp). My table looks something like the following (UNIX timestamps simplified):
+-----------------------------+
| id | date | thread_id |
+-----+---------+-------------+
| 1 | 1111 | 4 |
| 2 | 1333 | 4 |
| 3 | 1444 | 5 |
| 4 | 1666 | 5 |
+-----------------------------+
What I want to do is select thread IDs where ALL the items sharing the same thread ID are smaller than the passed date. So if I wanted thread IDs where ALL items are older than 1555 (date < 1555), I would only expect to have thread ID 4 returned, not 5 even though it's got an item with a date smaller than 1555. This is what I tried:
SELECT * FROM table WHERE date < 1555 GROUP BY thread_id ORDER BY date DESC
What I'm trying to do with that query is group all items by thread ID around the item with the highest date value and from there get the items where the date is less than 1555. But that doesn't work, it will still return thread ID 5 because it's got an item older than 1555.
So to summarize, how would I only select thread IDs where ALL items are older than a certain date?

SELECT thread_id FROM table GROUP BY thread_id HAVING MAX(date) < 1555

Use a HAVING clause. This allows you to filter on aggregates like SUM, MAX... Here you want to select only those thread id's whose newest entry is older than 1555, so you write:
SELECT * FROM table
GROUP BY thread_id
HAVING MAX(date) < 1555
ORDER BY date DESC

You can use having in place of where:
select customer_id,sum(amount),count(amount) from payment group by customer_id
having sum(amount)> 100

Related

Retrieve records using max and sum of time, if different users have same time, get the record with latest date created [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
Trying to retrieve records by first summing their time_spent, then using max to retrieve the largest record by time. which seems to be working.
I need to now check if on the chance that the sum of time_spent are the same value for users (a tie, like in the example below, both users have time_spent as 10 so it should then select the user that has the latest post), if they are then I need to only get the user_id that was posted last (newer) using the created_at column. I just don't know what to use to do that check, is it a CASE, or IF Function? and if so where would it go in my query?
Here is a sql fiddle link: http://sqlfiddle.com/#!9/f24985/2
Table1 layout
+----+---------+-----------+---------+------------+------------+
| id | user_id | member_id | item_id | time_spent | created_at |
+----+---------+-----------+---------+------------+------------+
| 1 | 1 | 1 | 1 | 5 | 2019-06-01 |
| 2 | 2 | 1 | 1 | 1 | 2019-06-07 |
| 3 | 2 | 1 | 1 | 5 | 2019-06-08 |
| 4 | 2 | 1 | 2 | 4 | 2019-06-01 |
| 5 | 1 | 1 | 2 | 5 | 2019-06-07 |
+----+---------+-----------+---------+------------+------------+
Current SQL:
SELECT
MAX(attribute_time.sum_time), attribute_time.user_id
FROM (
SELECT
SUM(time_spent) AS sum_time, user_id
FROM
table1
WHERE
member_id = 1
AND item_id IN (1, 2)
AND (created_at BETWEEN '2019-06-1' AND '2019-06-30')
GROUP BY
user_id
ORDER BY
sum_time desc
) AS attribute_time;
In this example, both users have a total of 10 for time, currently returns the first record of the 2 and not based on the created_at date, which in this case, should be user 2.
Expected
+---------+
| user_id |
+---------+
| 2 |
+---------+
This is what you are looking for. http://sqlfiddle.com/#!9/a5306c/4/0
The MAX clause is problematic for sub-queries involving quantities unless you use some repetitive and verbose queries (DRY!), as seen in answer here: MySQL: Select MAX() from sub-query with COUNT() - it seems to decouple the rows, so you get the highest (max) sum_time with the wrong id (I thought I was seeing things, seemed so simple)
I used LIMIT to get around it. Sorting descending (the highest on top), and then LIMITing the result to 1 achieves the same thing as "Max".
Also - Im not sure if in event of a tie in max time you wanted to pick the earliest or latest record, but this picks the latest. I use MAX to pick the last day/time for each user, and orderby sum_of_time, then by date. If you want the opposite, sub MIN for MAX and/or DESC for ASC in the order-by. Regards! Thx for the exercise.
SELECT
SUM(time_spent) AS sum_time, user_id, MAX(created_at)
FROM
Table1
WHERE
member_id = 1
AND item_id IN (1, 2)
AND (created_at BETWEEN '2019-06-1' AND '2019-06-30')
GROUP BY
user_id
ORDER BY
sum_time DESC, created_at DESC
LIMIT 1
Try to use this it will give you user id 2
SELECT
MAX(attribute_time.sum_time), attribute_time.user_id
FROM (
SELECT
SUM(time_spent) AS sum_time, user_id
FROM
table1
WHERE
member_id = 1
AND item_id IN (1, 2)
AND (created_at BETWEEN '2019-06-1' AND '2019-06-30')
GROUP BY
user_id
ORDER BY
sum_time,user_id desc
) AS attribute_time;

MAX function in MySQL does not return proper key value

I have a table called tbl_user_sal:
| id | user_id | salary | date |
| 1 | 1 | 1000 | 2014-12-01 |
| 2 | 1 | 2000 | 2014-12-02 |
Now I want to get the id of the maximum date. I used the following query:
SELECT MAX(date) AS from_date, id, user_id, salary
FROM tbl_user_sal
WHERE user_id = 1
But it gave me this output:
| id | user_id | salary | from_date |
| 1 | 1 | 2000 | 2014-12-02 |
Which is correct as far as the max date being 2014-12-02, but the corresponding id is not correct. This happens for other records as well. I used order by to check but that was not successful either. Can anyone shed some light on this?
Note: Its not necessary that max date will have max id, according to my needs. Records can have max date but id may be older.
If you only want to retrieve that information for a single user, which you seem to, because of your WHERE clause, just use ORDER BY and LIMIT:
SELECT *
FROM tbl_user_sal
WHERE user_id = 1
ORDER BY date DESC
LIMIT 1
If you want to do that for every user, however, you will have to get a little bit fancier. Something like that should do it:
SELECT t2.id, user_id, date
--find max date for each user_id
FROM (SELECT user_id, MAX(date) AS date
FROM tbl_user_sal
GROUP BY user_id) AS t1
--join ids for each max date/user_id combo
JOIN tbl_user_sal AS t2
USING (user_id, date)
--limit to 1 id for every user_id
GROUP BY
user_id
You are missing group by clause Try this:
select max(awrd_date) as from_date,awrd_id
from tbl_user_sal
where awrd_user_id = 106
group by awrd_id
What I believe you should do here is have a subquery that pulls the max date, and your outer query looks for the row with that date.
It looks like this:
SELECT *
FROM myTable
WHERE date = (SELECT MAX(date) FROM myTable);
Additional things may need to be added if you want to search for a specific user_id, or get the largest date for each user_id, but this gives your expected results for this example here.
Here is the SQL Fiddle.

Get one record per unique column value

I have a table that list system licences, multiple licences for each system (the expired ones and existing ones). I've only posted two columns in this question as they're the only important ones.
| id | systemid |
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 2 |
| 5 | 3 |
| 6 | 3 |
I need to get the rows with the id of 2, 4 and 6.
I need to collect 1 record for each systemid and it has to be the earliest (youngest) record, so in this case, the record with the highest id. I've been exploring GROUP BY, ORDER BY and LIMIT but I'm not producing the result I'm after. How do you collect one record for each individual value in one column and make sure it's the record with the highest id?
I KNOW this is wrong, but it's what I'm currently starring at:
SELECT * FROM licences GROUP BY systemid ORDER BY id DESC LIMIT 1
SELECT max(id), systemid FROM table GROUP BY systemid
Note that with a GROUP BY, all columns you select must either be in the GROUP BY clause or wrapped in an aggregating function, like max, min, sum, or average.
This will grab the highest id per systemid.
SELECT MAX(id), systemid
FROM ...
GROUP BY systemid

In mysql: how can I select the most recently added row when selecting by MAX if two values are equal (application is a games high score table)

I am trying to construct a highscore table from entries in a table with the layout
id(int) | username(varchar) | score(int) | modified (timestamp)
selecting the highest scores per day for each user is working well using the following:
SELECT id, username, MAX( score ) AS hiscore
FROM entries WHERE DATE( modified ) = CURDATE( )
Where I am stuck is that in some cases plays may achieve the same score multiple times in the same day, in which case I need to make sure that it is always the earliest one that is selected because 2 scores match will be the first to have reached that score who wins.
if my table contains the following:
id | username | score | modified
________|___________________|____________|_____________________
1 | userA | 22 | 2014-01-22 08:00:14
2 | userB | 22 | 2014-01-22 12:26:06
3 | userA | 22 | 2014-01-22 16:13:22
4 | userB | 15 | 2014-01-22 18:49:01
The returned winning table in this case should be:
id | username | score | modified
________|___________________|____________|_____________________
1 | userA | 22 | 2014-01-22 08:00:14
2 | userB | 22 | 2014-01-22 12:26:06
I tried to achieve this by adding ORDER BY modified desc to the query, but it always returns the later score. I tried ORDER BY modified asc as well, but I got the same result
This is the classic greatest-n-per-group problem, which has been answered frequently on StackOverflow. Here's a solution for your case:
SELECT e.*
FROM entries e
JOIN (
SELECT DATE(modified) AS modified_date, MAX(score) AS score
FROM entries
GROUP BY modified_date
) t ON DATE(e.modified) = t.modified_date AND e.score = t.score
WHERE DATE(e.modified) = CURDATE()
I think this would works for you and is the simplest way:
SELECT username, MAX(score), MIN(modified)
FROM entries
GROUP BY username
This returns this in your case:
"userB";22;"2014-01-22 12:26:06"
"userA";22;"2014-01-22 08:00:14"
However, I think what you want (in your example would be wrong) the most recent row. To do it, you need this:
SELECT username, MAX(score), MAX(modified)
FROM entries
GROUP BY username
Which returns:
"userB";22;"2014-01-22 18:49:01"
"userA";22;"2014-01-22 16:13:22"

ORDER BY on multiple conditions

I need a query that will give me the result that is either (a) the highest price or (b) the one with the oldest timestamp. In all cases, price should trump timestamp (ie if a record has a really old timestamp by higher price than all others, it should always return the record with the highest price)
Here are a few scenarios:
id | price | date
1 | 5 | 2012-02-20 08:59:06
2 | 5 | 2012-02-20 09:59:06
3 | 7 | 2012-02-20 10:59:06
Should return id 3 because it is highest price
id | price | date
1 | 5 | 2012-02-20 08:59:06
2 | 5 | 2012-02-20 09:59:06
3 | 5 | 2012-02-20 10:59:06
should return id 1 since it is the oldest
In my current query i am doing this:
SELECT * FROM table ORDER BY price, date DESC LIMIT 1
Unfortunately this query is not working how i've outlined it above.
Thanks for your help
I'm having trouble determining precisely what you are after, however it sounds like you are looking for the oldest timestamp for the highest price, and so the following should suffice
SELECT *
FROM table
ORDER BY
price DESC, // Favour the highest price
date ASC // Now get the one with oldest date at this price
LIMIT 1
i hope i understand your question, try this
SELECT
p.*
FROM table p
WHERE price = (SELECT MAX(price) FROM table)
OR date = (SELECT MIN(date) FROM table)