Group by last occurrence - mysql

i am trying to get the last rows where rec_p_id = 4 SORTED by the timestamp. Since i do not want to have all the results WHERE rec_p_id = 4, i am using GROUP BY to group it by send_p_id.
My SQL query looks like this:
SELECT *
FROM
( SELECT *
FROM chat
WHERE rec_p_id= "4"
ORDER
BY timestamp DESC) as sub
GROUP
BY send_p_id
My table looks like this:
Table chat
c_id
send_p_id
rec_p_id
timestamp
1
3
4
2020-05-01 14:46:00
2
3
4
2020-05-01 14:49:00
3
3
4
2020-05-01 14:50:00
4
7
4
2020-05-01 12:00:00
5
4
7
2020-05-01 12:10:00
6
7
4
2020-05-01 12:20:00
7
9
4
2020-05-01 16:50:00
8
9
4
2020-05-01 17:00:00
I want to get the last occurrences:
c_id
send_p_id
rec_p_id
timestamp
3
3
4
2020-05-01 14:50:00
6
7
4
2020-05-01 12:20:00
8
9
4
2020-05-01 17:00:00
But instead i get all the first ones:
c_id
send_p_id
rec_p_id
timestamp
1
3
4
2020-05-01 14:46:00
4
7
4
2020-05-01 12:00:00
7
9
4
2020-05-01 16:50:00
I saw the query i am using in this question: ORDER BY date and time BEFORE GROUP BY name in mysql
it seems to work for all of them. What am i doing wrong with my query?
Thanks in advance.

Looking to your expected result seems you are looking for
select max(c_id) c_id, send_p_id, min(timestamp) timestamp
from chat WHERE rec_p_id= "4"
group by send_p_id
ORDER BY c_id
Group by is for aggregated result ..
an use without aggregation function can produce unpredicatble result and in version > 5.6 can produce error

I used this answer and built this setup for you.
The code below is the copy of it, so that you can run it later yourself.
For the solution the example from the official manual.
CREATE TABLE chat
(
c_id INT PRIMARY KEY
, send_p_id INT
, rec_p_id INT
, timestamp DATETIME
);
INSERT INTO chat VALUES
(1, 3, 4, '2020-05-01 14:46:00')
, (2, 3, 4, '2020-05-01 14:49:00')
, (3, 3, 4, '2020-05-01 14:50:00')
, (4, 7, 4, '2020-05-01 12:00:00')
, (5, 4, 7, '2020-05-01 12:10:00')
, (6, 7, 4, '2020-05-01 12:20:00')
, (7, 9, 4, '2020-05-01 16:50:00')
, (8, 9, 4, '2020-05-01 17:00:00');
Solution:
SELECT c_id,
send_p_id,
rec_p_id,
timestamp
FROM chat AS c
WHERE timestamp=(SELECT MAX(c1.timestamp)
FROM chat AS c1
WHERE c.send_p_id = c1.send_p_id)
AND send_p_id != 4
ORDER BY timestamp;

Related

Calculate total in mysql

I want to add total sum of former broken and former crack for line 1 - 20 in December 2021. but now I only know this code
SELECT `line`, SUM(`FormerBroken`), SUM(`FormerCrack`) FROM `line_check` WHERE `Month` = '2021-12' AND `Line` = '1'
So is there any way that i can add line='2' , line='3',line='4'
my table for reference
Date
Line
Former Broken
Former Crack
1/12
1
3
2
2/12
2
5
4
3/12
3
7
6
4/12
4
9
8
5/12
5
10
10
6/12
1
3
2
7/12
2
5
4
8/12
3
7
6
9/12
4
9
8
You can use IN(...).
Example:
SELECT * FROM table WHERE someValue IN (1, 2, 3, 4);
Tailored to your existing query:
SELECT `line`, SUM(`FormerBroken`), SUM(`FormerCrack`) FROM `line_check` WHERE `Month` = '2021-12' AND `Line` IN ('1', '2', '3', '4');

Group By issue - 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

How to calculate the drawdown in Mysql with Window Functions?

I have this schema:
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`amount` int(11) DEFAULT NULL,
`group_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);
and i have populated that table with the following data:
insert into test (amount, group_id) values
(1,1), (3,1), (-4,1), (-2,1), (5,1), (10,1), (18,1), (-3,1),
(-5,1), (-7,1), (12,1), (-9,1), (6,1), (0,1), (185,2), (-150,2)
The table is:
# id, amount, group_id
1, 1, 1
2, 3, 1
3, -4, 1
4, -2, 1
5, 5, 1
6, 10, 1
7, 18, 1
8, -3, 1
9, -5, 1
10, -7, 1
11, 12, 1
12, -9, 1
13, 6, 1
14, 0, 1
15, 185, 2
16, -150, 2
This is the query i am using right now:
SELECT
t1.id,
t1.amount,
t1.cumsum,
(MAX(t1.cumsum) OVER (ORDER BY id RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) - t1.cumsum) as drawdown
FROM
(
SELECT
id,
amount,
group_id,
SUM(amount) OVER (ORDER BY id RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as cumsum
FROM
test
) as t1
order by drawdown desc
the query returns this output:
id, amount, cumsum, drawdown
10 -7 16 15
12 -9 19 12
9 -5 23 8
4 -2 -2 6
14 0 25 6
13 6 25 6
3 -4 0 4
8 -3 28 3
11 12 28 3
5 5 3 1
16 150 360 0
2 3 4 0
7 18 31 0
15 185 210 0
1 1 1 0
6 10 13 0
Just a fast clarification:
With the term "drawdown" (in this case) i mean the difference from the max cumsum of the value(field) AND the simple cumsum (cumulative sum).
I am not referring to any particular trading definition, i just need to difference between the biggest pick and the lowest. (obviously the highest pick must occour before the lowest = downtrend).
OK, my problem is that i need to group by the field group_id, if i add the group by clause on the query all the windows function will mess up.
RESULT EXPECTED:
I need to get a list grouped by group_id field that show the max drawdown for each group.
Edit: (#Akina)
group_id, drawdown
1 15
2 150

MySQL MAX() with GROUP BY

Considering these entries:
INSERT INTO `schedule_hours` (`id`, `weekday`, `start_hour`) VALUES
(1, 1, '09:00:00'),
(2, 2, '09:00:00'),
(3, 3, '09:00:00'),
(4, 4, '09:00:00'),
(5, 5, '09:00:00'),
(6, 6, NULL),
(7, 7, NULL),
(8, 1, '12:00:00');
I'm running the following query:
SELECT MAX(id), weekday, start_hour
FROM schedule_hours
GROUP BY weekday
ORDER BY weekday
The objective is to get a whole week (weekday 1-monday, 2-tuesday, etc...) but return the most recent entries.
So, in my table I now have 2 entries for Monday and 1 entry for the rest of the days, I only want to return the latest ones (id is an increment field), the right result should be:
8 1 12:00:00
2 2 09:00:00
3 3 09:00:00
4 4 09:00:00
5 5 09:00:00
6 6 NULL
7 7 NULL
What I'm currently getting:
8 1 09:00:00 < wrong
2 2 09:00:00
3 3 09:00:00
4 4 09:00:00
5 5 09:00:00
6 6 NULL
7 7 NULL
The id and weekday columns are correct, but the first row is showing a wrong result for the start_hour column!
You should try this query:
SELECT id, weekday, start_hour
FROM schedule_hours
WHERE id IN (
SELECT MAX(id)
FROM schedule_hours
GROUP BY weekday
)
ORDER BY weekday
Currently in your query, the columns in SELECT clause are different from the columns in GROUP BY clause. In standard SQL, your query is illegal and will result in a syntax error. However, MySQL extends the use of GROUP BY so that the select list can refer to nonaggregated columns not named in the GROUP BY clause, which is why you are not getting an error but the output is not what you are expecting. For more details, you may read MySQL Extensions to GROUP BY.
An alternative which avoids taking advantage of MySQL allowing a GROUP BY of a field which isn't in the SELECT statement:-
SELECT schedule_hours.id, schedule_hours.weekday, schedule_hours.start_hour
FROM schedule_hours
INNER JOIN
(
SELECT weekday, MAX(id) AS MaxId
FROM schedule_hours
GROUP BY weekday
)Sub1
ON schedule_hours.id = Sub1.MaxId
AND schedule_hours.weekday = Sub1.weekday
ORDER BY schedule_hours.weekday

Select all rows containing duplicate values in one of two columns from within distinct groups of related records

I'm trying to create a MySQL query that will return all individual rows (not grouped) containing duplicate values from within a group of related records. By 'groups of related records' I mean those with the same account number (per the sample below).
Basically, within each group of related records that share the same distinct account number, select just those rows whose values for the date or amount columns are the same as another row's values within that account's group of records. Values should only be considered duplicate from within that account's group. The sample table and ideal output details below should clear things up.
Also, I'm not concerned with any records with a status of X being returned, even if they have duplicate values.
Small sample table with relevant data:
id account invoice date amount status
1 1 1 2012-04-01 0 X
2 1 2 2012-04-01 120 P
3 1 2 2012-05-01 120 U
4 1 3 2012-05-01 117 U
5 2 4 2012-04-01 82 X
6 2 4 2012-05-01 82 U
7 2 5 2012-03-01 81 P
8 2 6 2012-05-01 80 U
9 3 7 2012-03-01 80 P
10 3 8 2012-04-01 79 U
11 3 9 2012-04-01 78 U
Ideal output returned from desired SQL query:
id account invoice date amount status
2 1 2 2012-04-01 120 P
3 1 2 2012-05-01 120 U
4 1 3 2012-05-01 117 U
6 2 4 2012-05-01 82 U
8 2 6 2012-05-01 80 U
10 3 8 2012-04-01 79 U
11 3 9 2012-04-01 78 U
Thus, row 7/9 and 8/9 should not both be returned because their duplicate values are not considered duplicate from within the scope of their respective accounts. However, row 8 should be returned because it shares a duplicate value with row 6.
Later, I may want to further hone the selection by grabbing only duplicate rows that have matching statuses, thus row 2 would be excluded because it does't match the other two found within that account's group of records. How much more difficult would that make the query? Would it just be a matter of adding a WHERE or HAVING clause, or is it more complicated than that?
I hope my explanation of what I'm trying to accomplish makes sense. I've tried using INNER JOIN but that returns each desired row more than once. I don't want duplicates of duplicates.
Table Structure and Sample Values:
CREATE TABLE payment (
id int(11) NOT NULL auto_increment,
account int(10) NOT NULL default '0',
invoice int(10) NOT NULL default '0',
date date NOT NULL default '0000-00-00',
amount int(10) NOT NULL default '0',
status char(1) NOT NULL default '',
PRIMARY KEY (id)
);
INSERT INTO payment VALUES (1, 1, 1, '2012-04-01', 0, 'X');
INSERT INTO payment VALUES (2, 1, 2, '2012-04-01', 120, 'P');
INSERT INTO payment VALUES (3, 1, 2, '2012-05-01', 120, 'U');
INSERT INTO payment VALUES (4, 1, 3, '2012-05-01', 117, 'U');
INSERT INTO payment VALUES (5, 2, 4, '2012-04-01', 82, 'X');
INSERT INTO payment VALUES (6, 2, 4, '2012-05-01', 82, 'U');
INSERT INTO payment VALUES (7, 2, 5, '2012-03-01', 81, 'p');
INSERT INTO payment VALUES (8, 2, 6, '2012-05-01', 80, 'U');
INSERT INTO payment VALUES (9, 3, 7, '2012-03-01', 80, 'U');
INSERT INTO payment VALUES (10, 3, 8, '2012-04-01', 79, 'U');
INSERT INTO payment VALUES (11, 3, 9, '2012-04-01', 78, 'U');
This type of query can be implemented as a semi join.
Semijoins are used to select rows from one of the tables in the join.
For example:
select distinct l.*
from payment l
inner join payment r
on
l.id != r.id and l.account = r.account and
(l.date = r.date or l.amount = r.amount)
where l.status != 'X' and r.status != 'X'
order by l.id asc;
Note the use of distinct, and that I'm only selecting columns from the left table. This ensures that there are no duplicates.
The join condition checks that:
it's not joining a row to itself (l.id != r.id)
rows are in the same account (l.account = r.account)
and either the date or the amount is the same (l.date = r.date or l.amount = r.amount)
For the second part of your question, you would need to update the on clause in the query.
This seems to work
select * from payment p1
join payment p2 on
(p1.id != p2.id
and p1.status != 'X'
and p1.account = p2.account
and (p1.amount = p2.amount or p1.date = p2.date))
group by p1.id
http://sqlfiddle.com/#!2/a50e9/3