Group By issue - Mysql - mysql

My table looks like this (and I'm using MySQL):
id NewID SenderID ReceiverID msg msgType TimeStamp
1 5 9 8 dfdf 1 7-03-2021 6:10 AM
2 4 9 8 dfdf 1 7-03-2021 6:11 AM
3 3 9 8 dfdf 1 7-03-2021 6:13 AM
4 5 9 8 fgdf 1 7-03-2021 6:16 AM
My target is to take id (_maxid) highest record to be on top in table, removing any duplicate record if that exists.
I m running following query,
SELECT MAX(id) _maxid , NewID
FROM tb_detail
GROUP BY id order by id desc
and it returns this-
_maxid NewID
4 5
3 3
2 4
1 5
Expected result:
_maxid NewID
4 5
3 3
2 4
Any ideas? Thank you.

Schema
create table tb_detail(id int, NewID int, SenderID int,ReceiverID int,msg varchar(10), msgType int, TimeStamp timestamp);
insert into tb_detail values(1, 5 , 9, 8 , 'dfdf', 1 ,'2021-7-03 6:10');
insert into tb_detail values(2 , 4 , 9 , 8 , 'dfdf' , 1 , '2021-7-03 6:11');
insert into tb_detail values(3 , 3 , 9 , 8 , 'dfdf' , 1 , '2021-7-03 6:13');
insert into tb_detail values(4 , 5, 9 , 8, 'fgdf' , 1, '2021-7-03 6:16');
Query #1
select max(id) _maxid,newid from tb_detail
group by newid
order by max(id) desc;
_maxid
newid
4
5
3
3
2
4
View on DB Fiddle

Related

Recursive CTE to traverse a hierarchy with dual descendant IDs

Given the following table of sports matches with two players:
match_id
match_date
p1_id
p2_id
1
01/01/2022
1
2
2
02/01/2022
3
1
3
03/01/2022
3
4
4
04/01/2022
2
3
5
05/01/2022
5
6
6
06/01/2022
1
2
7
07/01/2022
3
1
8
08/01/2022
3
4
9
09/01/2022
2
3
10
10/01/2022
5
6
11
11/01/2022
3
4
12
12/01/2022
7
8
13
13/01/2022
3
1
14
14/01/2022
5
7
15
15/01/2022
4
5
I’m trying to write a query with a recursive CTE that when given a match_id the query will return all match_id values for future matches for each of the two players. The recursion is needed because I need the query to also include all future matches for any of the future matches' players.
Using the example above and match_id = 6 then the two player IDs are 1 and 2. I need the query to return all future matches for these player IDs. This means the query needs to return 7, 9 and 13. However, in match_id = 7 player ID 1 plays player ID 3 so now all of their future match_id values from that point also need to be included. This means the query also needs to return 8 and 11. In match_id = 8 and match_id = 11 player ID 3 plays player ID 4 so the final match_id to be returned is 15.
The expected output is as follows:
match_id
7
8
9
11
13
15
I've written the following query:
WITH RECURSIVE match_ids AS (
SELECT
m1.match_id,
m1.match_date,
m1.p1_id,
m1.p2_id
FROM recursive_test AS m1
WHERE m1.match_id = 6
UNION ALL
SELECT
m2.match_id,
m2.match_date,
m2.p1_id,
m2.p2_id
FROM recursive_test AS m2
INNER JOIN match_ids
ON (
match_ids.p1_id = m2.p1_id
OR match_ids.p1_id = m2.p2_id
OR match_ids.p2_id = m2.p1_id
OR match_ids.p2_id = m2.p2_id
)
AND match_ids.match_date > m2.match_date
)
SELECT match_id
FROM match_ids
However, this returns:
match_id
6
2
4
1
1
2
3
1
2
1
Where might I be going wrong?
Here's the SQL to create the table:
CREATE TABLE `recursive_test` (
`match_id` int NOT NULL,
`match_date` date NOT NULL,
`p1_id` int NOT NULL,
`p2_id` int NOT NULL,
PRIMARY KEY (`match_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
INSERT INTO `recursive_test` VALUES (1,'2022-01-01',1,2),(2,'2022-01-02',3,1),(3,'2022-01-03',3,4),(4,'2022-01-04',2,3),(5,'2022-01-05',5,6),(6,'2022-01-06',1,2),(7,'2022-01-07',3,1),(8,'2022-01-08',3,4),(9,'2022-01-09',2,3),(10,'2022-01-10',5,6),(11,'2022-01-11',3,4),(12,'2022-01-12',7,8),(13,'2022-01-13',3,1),(14,'2022-01-14',5,7),(15,'2022-01-15',4,5);
WITH RECURSIVE
cte AS (
SELECT *
FROM recursive_test
WHERE match_id = #starting_match_id
UNION ALL
SELECT recursive_test.*
FROM recursive_test
JOIN cte ON recursive_test.match_date > cte.match_date
WHERE recursive_test.p1_id IN (cte.p1_id, cte.p2_id)
OR recursive_test.p2_id IN (cte.p1_id, cte.p2_id)
)
SELECT DISTINCT *
FROM cte;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=6ca1e57845bae995bacb04455beb6340

MySQL: Select top 5 rows based on ID and find Subtotal

Need to select top 5 rows for each id based on desc values of a particular column , value and find the subtotal of that column . for e.g (Tried creating the situation , actual table structure is large )
ID VALUE
1 2
1 3
1 4
1 5
1 6
1 7
1 8
2 9
2 10
2 11
2 12
2 13
2 14
Output Expected
ID VALUE
1 8
1 7
1 6
1 5
1 4
TOTAL 30
2 14
2 13
2 12
2 11
2 10
TOTAL 60
I could select top 5 rows using a code like this ;
#cust_rank := IF(#current_cust = id, #cust_rank + 1, 1) AS cust_rank,
#current_cust := id
and then selecting top 5
Also ,I could subtotal using code like this ;
SELECT id, value FROM source
UNION
SELECT NULL,SUM(value) FROM source
GROUP BY id ORDER BY id;
I need to merge both requirements .
SELECT CAST(id as CHAR(50)) Id, value
FROM (SELECT id , value ,
IF(#lastid=(#lastid:=id), #auto:=#auto+1, #auto:=1) indx
FROM source, (SELECT #lastid:=0, #auto:=1) A
ORDER BY id,value desc)as A
WHERE indx <= 5
Output
Id value
1 8
1 7
1 6
1 5
1 4
2 14
2 13
2 12
2 11
2 10
2nd Query
SELECT 'Total', SUM(value)
FROM (SELECT id , value ,
IF(#lastid=(#lastid:=id), #auto:=#auto+1, #auto:=1) indx
FROM source, (SELECT #lastid:=0, #auto:=1) A
ORDER BY value desc)as A
WHERE indx <= 5
GROUP BY id ;
Output
Total SUM(value)
Total 30
Total 60
Merged Query:
Select
CASE
WHEN indx =6 THEN "Total"
ELSE id
END as ID,value
from
(
select id,value,
IF(#lastid=(#lastid:=id), #auto:=#auto+1, #auto:=1) indx
FROM
(
SELECT CAST(id as CHAR(50)) Id, value
FROM (SELECT id , value ,
IF(#lastid=(#lastid:=id), #auto:=#auto+1, #auto:=1) indx
FROM source, (SELECT #lastid:=0, #auto:=1) A
ORDER BY id,value desc)as A
WHERE indx <= 5
UNION
SELECT CAST(id as CHAR(50))as id, SUM(value)as value
FROM (SELECT id , value ,
IF(#lastid1=(#lastid1:=id), #auto1:=#auto1+1, #auto1:=1) indx
FROM source, (SELECT #lastid1:=0, #auto1:=1) A
ORDER BY value desc)as A
WHERE indx <= 5
GROUP BY id)as output ,(SELECT #lastid:=0, #auto:=1) A ORDER BY id) as output1
Output
ID value
1 8
1 7
1 6
1 5
1 4
Total 30
2 10
2 11
2 12
2 13
2 14
Total 60

MySQL multiple count based on two column with multiple GROUP BY in single table

I have a query like below, it is working fine but not optimized, since it takes 1.5 sec to run. How to make this to an optimized result?
select h.keyword_id,
( select count(DISTINCT(user_id)) from history where category_id = 6
and h.keyword_id=keyword_id group by keyword_id ) as cat_6,
( select count(DISTINCT(user_id)) from history where category_id = 7
and h.keyword_id = keyword_id group by keyword_id ) as cat_7
from
history h group by h.keyword_id
History table
his_id keyword_id category_id user_id
1 1 6 12
2 1 6 12
3 1 7 12
4 1 7 12
5 2 6 13
6 2 6 13
7 2 7 13
8 3 6 13
Result:
keyword_id cat_6 cat_7
1 2 2 (unique users)
2 2 1
3 1 0
You can rewrite your query like this:
select h.keyword_id,
count(distinct if(category_id = 6, user_id, null)) as cat_6,
count(distinct if(category_id = 7, user_id, null)) as cat_7
from
history h
group by h.keyword_id
Your desired result based on the sample data is by the way false. In each keyword_id there's always just one distinct user_id.
you can see the query in action in an sqlfiddle here
For more optimization, you'd have to post the result of show create table history and the output of explain <your_query>;

How to split column based on row value in mysql?

I need a column from row value.
I have two table.
Table 1 : working_day Contains list of all working day date.
date
--------
2013-03-30
2013-03-29
2013-03-28
Table 2 : entry contains each employee in and out time.
id In Out Date
1 9 0 2013-03-30
2 8 0 2013-03-30
3 7 0 2013-03-30
1 8 18 2013-03-29
2 9 16 2013-03-29
3 6 20 2013-03-29
4 12 15 2013-03-29
Expected Output :
ID 29-03-2013_IN 29-03-2013_Out 30-03-2013_In
1 8 18 9
2 9 16 8
3 6 20 7
4 12 15 0
Tried :
SELECT id,
Case condition1 for 29_in, // I don't know which condition suite here.
Case condition1 for 29_out,
Case condition1 for 30_in
FROM entry
WHERE DATE
IN (
SELECT *
FROM (
SELECT DATE
FROM working_day
ORDER BY DATE DESC
LIMIT 0 , 2
)a
)
You could try something like that:
select
e.id,
(SELECT `in` FROM entry WHERE id = e.id AND date = '2013-03-30') as '2013-03-30_in',
(SELECT `in` FROM entry WHERE id = e.id AND date = '2013-03-29') as '2013-03-29_in',
(SELECT `out` FROM entry WHERE id = e.id AND date = '2013-03-29') as '2013-03-29_out'
from entry e
group by e.id;
Here is Demo
IMO you should do this in application instead of SQL

How to add duplicate rows using sql sum function

Few days ago, I came to a problem where I have to sum the value of some duplicate row in MySql & I've tried some queries but they didn't work.
Here is table data :-
card_id tic_id game_id card_symbol card_symbol_no qty
1 6 1 C 6 2
2 6 1 H 7 6
3 6 1 C 6 7
And My desired output is :-
card_id tic_id game_id card_symbol card_symbol_no qty
1 6 1 C 6 (9)
2 6 1 H 7 (6)
some other given factor :-
1.) the "tic_id", & "game_id" is same.
select
min(card_id) as card_id,
tic_id,
game_id,
card_symbol,
card_symbol_no,
sum(qty) as qty
from
yourTabel
group by
tic_id,
game_id,
card_symbol,
card_symbol_no