MySQL Max with wrong fields - mysql

When executing below query
SELECT `game_turns`.`in_darts`, `game_turns`.`date`, MAX(game_turns.score) AS max_score
FROM `game_turns`
JOIN `games` ON `games`.`id` = `game_turns`.`game_id` AND `games`.`training` = 1
WHERE `game_turns`.`uid` = 2
AND `game_turns`.`out` = 1
AND `game_turns`.`in_darts` = 3
ORDER BY `game_turns`.`score` DESC
LIMIT 1
I get the max score for that user id (uid) and out in 3 darts, but the rest (date) is wrong.
Fields are
Score Uid GameID Score out in_darts date
121 2 4 8 1 3 2015-07-21 13:52:12
8465 2 142 100 1 3 2015-09-05 19:46:29
It returns the score 100 from row ID 8465 but the rest is from row ID 121
I have googled it and came on some Stackoverflow results saying that I should use ORDER BY and LIMIT 1, but looks like it aint working for me.
Order by Date also didn't do the trick.

A simple order by and limit should do what you want:
SELECT gt.`in_darts`, gt.`date`, gt.score
FROM `game_turns` gt JOIN
`games` g
ON g.`id` = gt.`game_id` AND g.`training` = 1
WHERE gt.`uid` = 2 AND gt.`out` = 1 AND gt.`in_darts` = 3
ORDER BY gt.`score` DESC
LIMIT 1;
There is no need for aggregation.

If seeking a solution that would work for multiple UID's then aggregation becomes useful - via a subquery.
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE Table1
(`Score_A` int, `Uid` int, `GameID` int, `Score_B` int, `out` int, `in_darts` int, `date` datetime)
;
INSERT INTO Table1
(`Score_A`, `Uid`, `GameID`, `Score_B`, `out`, `in_darts`, `date`)
VALUES
(121, 2, 4, 8, 1, 3, '2015-07-21 13:52:12'),
(8465, 2, 142, 100, 1, 3, '2015-09-05 19:46:29')
;
Query 1:
SELECT
t.*
FROM table1 t
INNER JOIN (
SELECT Uid, max(Score_B) as Score_B
FROM table1
GROUP BY uid
) msb ON t.Uid = msb.Uid and t.Score_B = msb.Score_B
Results:
| Score_A | Uid | GameID | Score_B | out | in_darts | date |
|---------|-----|--------|---------|-----|----------|-----------------------------|
| 8465 | 2 | 142 | 100 | 1 | 3 | September, 05 2015 19:46:29 |

Related

Finding time difference based on distinct ids in mySQL

I would like to find the day difference between the latest and the 2nd latest distinct order_id for each user.
The intended output would be:
user_id | order_diff
1 | 1
3 | 7
8 | 1
order_diff represents the difference in days between 2 distinct order_id. In the event that there are no two distinct order_id (as in the case for user id 9), the result is not returned.
In this case, the order_diff for user_id 1 is 1 since the day difference between his 2 distinct order_id is 1. However, there is no order_diff for user_id 9 since he has no 2 distinct `order_id'.
This is the dataset:
user_id order_id order_time
1 208965785 2016-12-15 17:14:13
1 201765785 2016-12-14 17:19:05
1 203932785 2016-12-13 20:41:30
1 209612785 2016-12-14 20:14:32
1 208112785 2016-12-14 20:27:08
1 205525785 2016-12-14 17:01:26
1 208812785 2016-12-14 20:18:23
1 206432785 2016-12-11 20:32:20
1 206698785 2016-12-14 10:50:15
2 209524795 2016-11-26 18:06:21
3 206529925 2016-10-01 10:43:57
3 203729925 2016-10-08 10:43:11
4 204876145 2016-09-24 10:23:49
5 203363157 2016-07-13 23:56:43
6 207784875 2017-01-04 12:21:21
7 206437177 2016-06-25 02:40:33
8 202819645 2016-09-09 11:47:27
8 202819645 2016-09-09 11:47:27
8 202819646 2016-09-08 11:47:27
9 205127187 2016-06-05 22:21:18
9 205127187 2016-06-05 22:21:18
11 207874877 2016-06-17 16:49:44
12 204927595 2016-11-28 23:05:40
This is the code that I am currently using:
SELECT e1.user_id,datediff(e1.order_time,e2.time), e1.order_id FROM
sales e1
JOIN
sales e2
ON
e1.user_id=e2.user_id
AND
e1.order_id = (SELECT distinct order_id FROM sales temp1 WHERE temp1.order_id =e1.order_id ORDER BY order_time DESC LIMIT 1)
AND
e2.order_id = (SELECT distinct order_id FROM sales temp2 WHERE temp2.order_id=e2.order_id ORDER BY order_time DESC LIMIT 1 OFFSET 1)
My output does not produce the desired output and it also ignores the cases where order_ids are the same.
Edit: I would also like the query to be extended to larger datasets where the 2nd most recent order_time may not be the min(order_time)
Based on your fiddle:
select user_id,
datediff(max(order_time),
( -- Scalar Subquery to get the 2nd largest order_time
select max(order_time)
from orders as o2
where o2.user_id = o.user_id -- same user
and o2.order_time < max(o.order_time) -- but not the max time
)
) as diff
from orders as o
group by user_id
having diff is not null -- if there's no 2nd largest time diff will be NULL
Following would work:
Schema (MySQL v5.7)
CREATE TABLE orders
(`user_id` int, `order_id` int, `order_time` datetime)
;
INSERT INTO orders
(`user_id`, `order_id`, `order_time`)
VALUES
(1,208965785,'2016-12-15 17:14:13'),
(1,201765785,'2016-12-14 17:19:05'),
(1,203932785,'2016-12-13 20:41:30'),
(1,209612785,'2016-12-14 20:14:32'),
(1,208112785,'2016-12-14 20:27:08'),
(1,205525785,'2016-12-14 17:01:26'),
(1,208812785,'2016-12-14 20:18:23'),
(1,206432785,'2016-12-11 20:32:20'),
(1,206698785,'2016-12-14 10:50:15'),
(2,209524795,'2016-11-26 18:06:21'),
(3,206529925,'2016-10-01 10:43:57'),
(3,203729925,'2016-10-08 10:43:11'),
(4,204876145,'2016-09-24 10:23:49'),
(5,203363157,'2016-07-13 23:56:43'),
(6,207784875,'2017-01-04 12:21:21'),
(7,206437177,'2016-06-25 02:40:33'),
(8,202819645,'2016-09-09 11:47:27'),
(8,202819645,'2016-09-09 11:47:27'),
(8,202819646,'2016-09-08 11:47:27'),
(9,205127187,'2016-06-05 22:21:18'),
(9,205127187,'2016-06-05 22:21:18'),
(11,207874877,'2016-06-17 16:49:44'),
(12,204927595,'2016-11-28 23:05:40');
Query #1
SELECT dt2.user_id,
MIN(datediff(dt2.latest_order_time,
dt2.second_latest_order_time)) AS order_diff
FROM (
SELECT o.user_id,
o.order_time AS latest_order_time,
(SELECT o2.order_time
FROM orders AS o2
WHERE o2.user_id = o.user_id AND
o2.order_id <> o.order_id
ORDER BY o2.order_time DESC LIMIT 1) AS second_latest_order_time
FROM orders AS o
JOIN (SELECT user_id, MAX(order_time) AS latest_order_time
FROM orders
GROUP BY user_id) AS dt
ON dt.user_id = o.user_id AND
dt.latest_order_time = o.order_time
) AS dt2
WHERE dt2.second_latest_order_time IS NOT NULL
GROUP BY dt2.user_id;
| user_id | order_diff |
| ------- | ---------- |
| 1 | 1 |
| 3 | 7 |
| 8 | 1 |
View on DB Fiddle
Details:
We determine maximum order_time for a user_id in a sub-select query (Derived Table). We can alias it as latest_order_time.
We Join this result-set to the orders table. This will help us in considering only the row(s) with maximum value of order_time for a user_id.
Now, we use a Correlated Subquery to determine the maximum order_time value for the same user, out of the rest of order_id value(s). We can alias it as second_latest_order_time.
Finally, use this as a Derived Table again, and remove all the cases where second_latest_order_time is null, and calculate datediff() for the rest.
A final Group By is needed, as your data has multiple entries for a
Here is the solution:
SELECT user_id,
DATEDIFF(MAX(order_time), MIN(order_time)) as order_diff
FROM orders
GROUP BY user_id
HAVING order_diff > 0;
Here is a link to test it.

Custom query with group by and then count

I am using events.I would like to know how to calculate sum in event or using single query
http://sqlfiddle.com/#!9/ad6d1c/1
DDL for question:
CREATE TABLE `table1` (
`id` int(11) NOT NULL,
`group_id` int(11) NOT NULL DEFAULT '0',
`in_use` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0->in_use,1->not_in_use',
`auto_assign` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0->Yes,1->No'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `table1`
ADD PRIMARY KEY (`id`);
ALTER TABLE `table1`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
INSERT INTO `table1` (`id`, `group_id`, `in_use`, `auto_assign`) VALUES
(1, 3, 1, 0),(2, 2, 0,1),(3, 1, 1, 1),(4, 3, 1, 0),(5, 3, 0, 0),(6, 3, 0, 1),
(7, 3, 1, 0),(8, 3, 0, 1),(9, 3, 0, 1),(10, 3, 0, 1),(11, 3, 0, 1),(12, 3, 1, 1),
(13, 3, 1, 0),(14, 3, 0, 0),(15, 3, 0, 0),(16, 3, 0, 0),(17, 3, 0, 0),(18, 3, 1, 1),
(19, 3, 0, 0),(20, 3, 0, 0)
Expected Output :
| count | in_use | auto_assign | sum | check_count |
|-------|--------|-------------|------|------------ |
| 7 | 0 | 0 | 11 | 5 |
| 5 | 0 | 1 | 07 | 3 |
| 4 | 1 | 0 | 11 | 5 |
| 2 | 1 | 1 | 07 | 3 |
Here we can see that auto_assign=0 have total 11 count(7+4) and
auto_assign=1 have 7 count(5+2) this count should be stored into new column sum.
check_count column is percentage value of sum column.Percentage will be predefined.
Lets take 50%, So count 11(sum column value) ->50% = 5.5 = ROUND(5.5) == 5(In integer). Same way count 7(sum column value)->50% = 3.5 =ROUND(3.5)=3(Integer)
Here 5 > 4(auto_assign=0 and in_use=1 ).So have to insert record into another table(table2). if not then not.
Same way, If 3 >2 then also need to insert record into another table(table2).if not then not.
Note : This logic I would like to implement in event
This is bit complicated, but please suggest me how to do this in event.
Detail clarification :
here percentage_Value is 5 for auto_assign =0.But auto_assign=0 and in_use=1 have count is 4 which less than 5 ,then have to insert record into table 2.
suppose,if we get count is 6 for auto_assign=0 and in_use=1 ,Then no need to insert record into table2.
Same way,
here percentage_Value is 3 for auto_assign =1.But auto_assign=1 and in_use=1 have count is 2 which less than 3 ,then have to insert record into table 2.
suppose,if we get count is 4 for auto_assign=1 and in_use=1 ,Then no need to insert record into table2.
Insert query into table2:
Insert into table2(cli_group_id,auto_assign,percentage_value,result_value) values(3,0,5,4)
DEMO Fiddle
Break the problem down: we need a count of the records by auto_Assigns; so we generate a derived table (B) with that value and join back to your base table on auto_Assign. This then gives us the column we need for some and we use the truncate function and a division model to get the check_count
SELECT count(*), in_use, A.Auto_Assign, B.SumC, truncate(B.SumC/2,0) as check_Count
FROM table1 A
INNER JOIN (Select Auto_Assign, count(*) sumC
from table1
where Group_ID = 3
Group by Auto_Assign) B
on A.Auto_Assign = B.Auto_Assign
WHERE GROUP_ID = 3
Group by in_use, A.Auto_Assign
we can eliminate the double where clause by joining on it:
SELECT count(*), in_use, A.Auto_Assign, B.SumC, truncate(B.SumC/2,0) as check_Count
FROM table1 A
INNER JOIN (Select Auto_Assign, count(*) sumC, Group_ID
from table1
where Group_ID = 3
Group by Auto_Assign, Group_ID) B
on A.Auto_Assign = B.Auto_Assign
and A.Group_ID = B.Group_ID
Group by in_use, A.Auto_Assign
I'd need clarification on the rest of the question: I'm not sure what 5 > 4 your'e looking at and I see no 3 other than the check count but that's not "the same way" so I'm not sure what you're after.
Here 5 > 4(auto_assign=0 and in_use=1 ).So have to insert record into another table(table2). if not then not.
Same way, If 3 >2 then also need to insert record into another table(table2).if not then not.
Note : This logic I would like to implement in event
This is bit complicated, but please suggest me how to do this in event.
So to create the event: DOCS
Which results in:
CREATE EVENT myevent
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 6 Minutes
DO
INSERT INTO table2
SELECT count(*) as mCount
, in_use
, A.Auto_Assign
, B.SumC, truncate(B.SumC/2,0) as check_Count
FROM table1 A
INNER JOIN (SELECT Auto_Assign, count(*) sumC, Group_ID
FROM table1
WHERE Group_ID = 3
GROUP BY Auto_Assign, Group_ID) B
ON A.Auto_Assign = B.Auto_Assign
AND A.Group_ID = B.Group_ID
GROUP BY in_use, A.Auto_Assign

how to get last row from table 2 using left join mysql

I have tow tables tbl_product_checkout and tbl_product_checkout_status in which I want to get the last row from tbl_product_checkout_status
//tbl_product_checkout
product_checkout_id user_id product_checkout_order_no
-----------------------------------------------------------
1 1 ORD123456
//tbl_product_checkout_status
checkout_status_id product_checkout_id checkout_status_check
------------------------------------------------------------------
1 1 Dispatched
2 1 Delivered
I have tried using the following query
SELECT *
FROM tbl_product_checkout pc
LEFT
JOIN tbl_product_checkout_status cs
ON cs.product_checkout_id = pc.product_checkout_id
WHERE pc.user_id = 1
GROUP
BY pc.product_checkout_id
ORDER
BY cs.checkout_status_id DESC
but the output for above query is,
user_id product_checkout_order_no checkout_status_check
-------------------------------------------------------------
1 ORD123456 Dispatched
but I want the result as,
user_id product_checkout_order_no checkout_status_check
-------------------------------------------------------------
1 ORD123456 Delivered
Add a where = max sub query eg
DROP TABLE IF EXISTS tbl_product_checkout,tbl_product_checkout_status;
CREATE TABLE tbl_product_checkout(product_checkout_id INT, user_id INT, product_checkout_order_no VARCHAR(20));
INSERT INTO tbl_product_checkout VALUES
( 1 , 1 , 'ORD123456');
CREATE TABLE tbl_product_checkout_status(checkout_status_id INT, product_checkout_id INT, checkout_status_check VARCHAR(20));
INSERT INTO tbl_product_checkout_status VALUES
( 1 , 1 , 'Dispatched'),
( 2 , 1 , 'Delivered');
SELECT * FROM
tbl_product_checkout T1
LEFT JOIN tbl_product_checkout_status T2 ON T1.PRODUCT_CHECKOUT_ID = T2.PRODUCT_CHECKOUT_ID
WHERE T2.CHECKOUT_STATUS_ID = (
SELECT MAX(T3.CHECKOUT_STATUS_ID)
FROM tbl_product_checkout_status T3
WHERE T3.PRODUCT_CHECKOUT_ID = T2.PRODUCT_CHECKOUT_ID
)
;
Result
+---------------------+---------+---------------------------+--------------------+---------------------+-----------------------+
| product_checkout_id | user_id | product_checkout_order_no | checkout_status_id | product_checkout_id | checkout_status_check |
+---------------------+---------+---------------------------+--------------------+---------------------+-----------------------+
| 1 | 1 | ORD123456 | 2 | 1 | Delivered |
+---------------------+---------+---------------------------+--------------------+---------------------+-----------------------+
1 row in set (0.00 sec)
I think your group by mess up your desired outcome. I worked on your given database schema and cretaed a fiddle and managed to get your desired outcome. So your sql should be something like this:
SELECT * FROM tbl_product_checkout as pc
LEFT JOIN tbl_product_checkout_status as cs ON
cs.product_checkout_id = pc.product_checkout_id
WHERE pc.user_id = 1 ORDER BY cs.checkout_status_id DESC limit 1
By using limit 1, you will get last row as we ordered by DESC.
Keep in mind that i removed date part since there was no date on your example code.
Check Out Fiddle

How to select a row with maximum value for a column in MySQL?

*None of other available answers solved my problem
I have a table t like this
id,cc,count
'1','HN','22'
'1','US','18'
'1','VN','1'
'2','DK','2'
'2','US','256'
'3','SK','1'
'3','US','66310'
'4','UA','2'
'4','US','263'
'6','FR','7'
'6','US','84'
'9','BR','3'
I want to get the rows for ids with maximum count, like below:
id,cc,count
'1','HN','22'
'2','US','256'
'3','US','66310'
'4','US','263'
'6','US','84'
'9','BR','3'
My current code is like this but I am not getting the expected results:
SELECT t.* FROM t
JOIN (
SELECT
t.id,t.cc
,max(t.count) as max_slash24_count
FROM t
group by t.id,t.cc
) highest
ON t.count = highest.max_slash24_count
and t.cc = highest.cc
Can anybody help me out?
Remove CC column from group by. Try this.
SELECT t.* FROM t
JOIN (
SELECT
t.id
,max(t.count) as max_slash24_count
FROM t
group by t.id
) highest
ON t.count = highest.max_slash24_count
and t.id= highest.id
Try this:
create table t (id varchar(10), cc varchar(10), count varchar(10))
insert into t (id,cc,count) values ('1','HN','22');
insert into t (id,cc,count) values ('1','US','18');
insert into t (id,cc,count) values ('1','VN','1');
insert into t (id,cc,count) values ('2','DK','2');
insert into t (id,cc,count) values ('2','US','256');
insert into t (id,cc,count) values ('3','SK','1');
insert into t (id,cc,count) values ('3','US','66310');
insert into t (id,cc,count) values ('4','UA','2');
insert into t (id,cc,count) values ('4','US','263');
insert into t (id,cc,count) values ('6','FR','7');
insert into t (id,cc,count) values ('6','US','84');
insert into t (id,cc,count) values ('9','BR','3');
select *
from t
where exists (
select *
from t as t1
group by t1.id
having t1.id = t.id and max(t1.count) = t.count
)
Result
ID CC COUNT
-------------
1 HN 22
2 US 256
3 US 66310
4 US 263
6 US 84
9 BR 3
Check SQLFiddle
This question was answered a lot of times on SO. The query is as simple as this:
SELECT m.id, m.cc, m.count
FROM t m # "m" from "max"
LEFT JOIN t b # "b" from "bigger"
ON m.id = b.id # match a row in "m" with a row in "b" by `id`
AND m.count < b.count # match only rows from "b" having bigger count
WHERE b.count IS NULL # there is no "bigger" count than "max"
The real issue on your question is about the column types. If count is char (and not int) then the string comparison happens using the dictionary order, not the numeric order.
For example, if the third row reads:
'1','VN','123'
you might expect it to be selected in the output, because 123 is bigger than 22. This does not happen because, as string, '123' is smaller than '22'.
Even tho, this was already answered, using ROW_NUMBER functionality as in SQL Server is quite fun and interesting: please look at this query:
SELECT TT.Id, TT.cc, TT.count
FROM (
SELECT t.cc
, t.count
, #row_number:=CASE WHEN #Id=Id THEN #row_number+1 ELSE 1 END AS row_number
, #Id:=Id AS Id
FROM t, (SELECT #row_number:=0, #Id:='') AS temp
ORDER BY t.Id, t.count DESC
) AS TT
WHERE TT.row_number = 1
ORDER BY TT.Id;
It produces expected output:
| Id | cc | count |
|----|----|-------|
| 1 | HN | 22 |
| 2 | US | 256 |
| 3 | US | 66310 |
| 4 | US | 263 |
| 6 | US | 84 |
| 9 | BR | 3 |
SQLFiddle
I've taken test data from #Andrey Morozov

How to use multiple IN - Where IN (...) and IN (...)

I'm tuning performance of my script and I changed the way posts categories are sorted.
I was using successfully the following query.
It selects posts with (130|3|4|5) categories and checks if it also has (73) category init as one post can have multiple categories.
SELECT *
FROM post
LEFT JOIN post_plus
ON ( post.id = post_plus.news_id )
WHERE category REGEXP '[[:<:]](130|3|4|5)[[:>:]]'
AND category REGEXP '[[:<:]](73)[[:>:]]'
AND approve = 1
ORDER BY fixed DESC,
date DESC
LIMIT 0, 7
Now with a new query I need to perform multiple IN (...) queries instead of AND category REGEXP '...', but for some reason additional AND categoryid IN always returns empty result.
SELECT *
FROM post
LEFT JOIN post_plus
ON ( post.id = post_plus.news_id )
LEFT JOIN post_category
ON ( post_category.postid = post.id )
WHERE categoryid IN ( 130, 3, 4, 5 )
AND categoryid IN ( 73 )
AND approve = 1
ORDER BY fixed DESC,
date DESC
LIMIT 0, 7;
post_category structure
+-----+--------+------------+
| cid | postId | categoryId |
+-----+--------+------------+
| 824 | 7 | 10 |
| 825 | 7 | 13 |
| 826 | 7 | 16 |
| 827 | 7 | 29 |
| 828 | 7 | 71 |
+-----+--------+------------+
To get the postid for posts that are both in category 73 and in at least one of category id 130, 3, 4, 5 you can use
SELECT postid
FROM post_category
GROUP BY postid
HAVING MAX(CASE
WHEN categoryid = 73 THEN 1
END) = 1
AND MAX(CASE
WHEN categoryid IN ( 130, 3, 4, 5 ) THEN 1
END) = 1
This can be used in a derived table to join onto your wider query.
Or another possibility is
SELECT c1.postid
FROM post_category c1
JOIN post_category c2
ON c1.postid = c2.postid
WHERE c1.categoryid IN ( 130, 3, 4, 5 )
AND c2.categoryid = 73
You can use an INTERSECT-compound statement:
SELECT postid
FROM post_category
WHERE categoryid = 73
INTERSECT
SELECT postid
FROM post_category
WHERE categoryid IN (130, 3, 4, 5)
This will select only those postids that have a categoryid equal to 73 and at least one of categoryid = 130, 3, 4, or 5.
This query will probably run faster than a aggregate-query (GROUP BY), since the sql-server can use the index on categoryid (which you hopefully have) to get the relevent postids and then uses a temporary index to compute the intersection (at least thats what sqlite does). If there there are no postids with categoryid 73, then the second part of the query is never executed, since the intersection of an empty set with anything else is always just the empty set.
To get your posts, use a subquery:
SELECT post.*
FROM post
WHERE post.id IN (SELECT postid
FROM post_category
WHERE categoryid = 73
INTERSECT
SELECT postid
FROM post_category
WHERE categoryid IN (130, 3, 4, 5))
Also note that you can add more INTERSECT-compounds as you like.