SQL MAX function - mysql

I have a table containing the primary key NoticeID, the NoticeDate and the notice itself. I wanted to make a query which would find the NoticeDate and notice of the row with the greatest NoticeID.
I tired this:
SELECT NoticeDate, Notice FROM notices WHERE NoticeID=(SELECT MAX(NoticeID))
It just returns the all of the rows.
Please help.

What's important here is that the greatest NoticeID is applied to groups of NoticeDate, implying the need for a GROUP BY.
There are a few ways of approaching a query to get one full record per group (your group is NoticeDate). Probably the easiest is an IN () subquery which returns the MAX(NoticeID) per group:
SELECT
NoticeDate,
Notice
FROM
notices
WHERE
NoticeID IN (SELECT MAX(NoticeID) FROM notices GROUP BY NoticeDate)
That may not be the fastest, however. You may also join against a subquery returning that same MAX(NoticeID). In this case, the subquery produces a table of NoticeID which is joined back to the full table to retrieve the remaining columns for the row it matches when joining.
SELECT
n.NoticeDate,
n.Notice
FROM
notices n
JOIN (
-- Join a subquery to get the max NoticeID per group
SELECT MAX(NoticeID) AS maxid
FROM notices
GROUP BY NoticeDate
) nmax ON n.NoticeID = nmax.maxid

If you want only one row back, then I think the easiest approach is using order by and limit:
SELECT n.*
FROM notices n
ORDER BY NoticeId DESC
LIMIT 1;

Related

MySQL GROUP BY ignores the ORDER BY and always returns the 1st row

I have read through tons of similar questions and none is answering what is wrong with mine.
I want to select the entire row that includes the maximum value of one of the columns for each group.
SELECT * FROM (
SELECT t1.* FROM `t1` JOIN `t2` ON t2.id=t1.raceId ORDER BY t1.points DESC
) AS new GROUP BY new.athleteId ORDER BY new.points DESC
This works, giving me a single row for each athlete, but the row it shows is just the earliest row in the DB, not the row with the maximum points.
The sub query alone shows all the rows in the correct order, but when I try to group them, it still takes the earliest row and ignores the ordering.
I can retrieve the maximum points for each grouping, but the rest of the row info still comes from the earliest entry.
The GROUP BY clause is meant to be used with aggeregate functions.
What is it that you are trying to achieve with the GROUP BY?
Maybe one way to achieve what you're after..
As a general rule of thumb; it's wise if you're using a "GROUP BY" to define what aggregate functions to use. MySQL allows you to group by without aggerate functions defined but i've found this to be very confusing whiteout being very specific on what I want to aggregate on. Maybe it's because of my background in SQL server and oracle; which DO NOT allow you to use a group by this way...
essentially get the max points for each athlete then join back to your entire data set to limit by that athlete and points. may need to do it by race if you want athlete by race as well, i'm unsure if you want max athlete points by race, but based on the group by/order by I'm guessing not.
SELECT t1.*, t2.*
FROM (SELECT athlete, max(t1.points)
FROM `t1`
INNER JOIN `t2` ON t2.id=t1.raceId
GROUP BY athlete) new
INNER JOIN `t1` on T1.athletID = new.athletID
and t1.points = new.points
INNER JOIN JOIN `t2` ON t2.id=t1.raceId
ORDER BY new.points DESC
Another way depending on version of mySQL would be to use analytic functions along with aggregate functions... but w/o version number, i'll not go into detail.

How to improve performance getting recent records to display in list, recent top 5 most

I'm making a sample recent screen that will display a list, it displays the list, with id set as primary key.
I have done the correct query as expected but the table with big amount of data can cause slow performance issues.
This is the sample query below:
SELECT distinct H.id -- (Primary Key),
H.partnerid as PartnerId,
H.partnername AS partner, H.accountname AS accountName,
H.accountid as AccountNo,
FROM myschema.mytransactionstable H
INNER JOIN (
SELECT S.accountid, S.partnerid, S.accountname,
max(S.transdate) AS maxDate
from myschema.mytransactionstable S
group by S.accountid, S.partnerid, S.accountname
) ms ON H.accountid = ms.accountid
AND H.partnerid = ms.partnerid
AND H.accountname =ms.accountname
AND H.transdate = maxDate
WHERE H.accountid = ms.accountid
AND H.partnerid = ms.partnerid
AND H.accountname = ms.accountname
AND H.transdate = maxDate
GROUP BY H.partnerid,H.accountid, H.accountname
ORDER BY H.id DESC
LIMIT 5
In my case, there are values which are similar in the selected columns but differ only in their id's
Below is a link to an image without executing the query above. They are all the records that have not yet been filtered.
Sample result query click here
Since I only want to get the 5 most recent by their id but the other columns can contain similar values
accountname,accountid,partnerid.
I already got the correct query but,
I want to improve the performance of the query. Any suggestions for the improvement of query?
You can try using row_number()
select * from
(
select *,row_number() over(order by transdate desc) as rn
from myschema.mytransactionstable
)A where rn<=5
Don't repeat ON and WHERE clauses. Use ON to say how the tables (or subqueries) are "related"; use WHERE for filtering (that is, which rows to keep). Probably in your case, all the WHERE should be removed.
Please provide SHOW CREATE TABLE
This 'composite' index would probably help because of dealing with the subquery and the JOIN:
INDEX(partnerid, accountid, accountname, transdate)
That would also avoid a separate sort for the GROUP BY.
But then the ORDER BY is different, so it cannot avoid a sort.
This might avoid the sort without changing the result set ordering: ORDER BY partnerid, accountid, accountname, transdate DESC
Please provide EXPLAIN SELECT ... and EXPLAIN FORMAT=JSON SELECT ... if you have further questions.
If we cannot get an index to handle the WHERE, GROUP BY, and ORDER BY, the query will generate all the rows before seeing the LIMIT 5. If the index does work, then the outer query will stop after 5 -- potentially a big savings.

Mysql DISTINCT with more than one column (remove duplicates)

My database is called: (training_session)
I try to print out some information from my data, but I do not want to have any duplicates. I do get it somehow, may someone tell me what I do wrong?
SELECT DISTINCT athlete_id AND duration FROM training_session
SELECT DISTINCT athlete_id, duration FROM training_session
It works perfectly if i use only one column, but when I add another. it does not work.
I think you misunderstood the use of DISTINCT.
There is big difference between using DISTINCT and GROUP BY.
Both have some sort of goal, but they have different purpose.
You use DISTINCT if you want to show a series of columns and never repeat. That means you dont care about calculations or group function aggregates. DISTINCT will show different RESULTS if you keep adding more columns in your SELECT (if the table has many columns)
You use GROUP BY if you want to show "distinctively" on a certain selected columns and you use group function to calculate the data related to it. Therefore you use GROUP BY if you want to use group functions.
Please check group functions you can use in this link.
https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html
EDIT 1:
It seems like you are trying to get the "latest" of a certain athlete, I'll assume the current scenario if there is no ID.
Here is my alternate solution:
SELECT a.athlete_id ,
( SELECT b.duration
FROM training_session as b
WHERE b.athlete_id = a.athlete_id -- connect
ORDER BY [latest column to sort] DESC
LIMIT 1
) last_duration
FROM training_session as a
GROUP BY a.athlete_id
ORDER BY a.athlete_id
This syntax is called IN-SELECT subquery. With the help of LIMIT 1, it shows the topmost record. In-select subquery must have 1 record to return or else it shows error.
MySQL's DISTINCT clause is used to filter out duplicate recordsets.
If your query was SELECT DISTINCT athlete_id FROM training_session then your output would be:
athlete_id
----------
1
2
3
4
5
6
As soon as you add another column to your query (in your example, the column called duration) then each record resulting from your query are unique, hence the results you're getting. In other words the query is working correctly.

Why does HAVING MAX() return a different value than SELECT MAX()?

I have a table log that contains, among others, a DateTime column called TimeOfLog and a foreign key Logger_ID.
What I was trying to do was get the newest entry per Logger_ID.
SELECT l.TimeOfLog AS TimeOfLog, l.Logger_ID AS Logger_ID
FROM `log` `l`
GROUP BY l.Logger_ID
HAVING MAX(l.TimeOfLog)
this however returns more or less a random TimeOfLog belonging to that Logger_ID. If I then run
SELECT MAX(l.TimeOfLog) AS TimeOfLog, l.Logger_ID AS Logger_ID
FROM `log` `l`
GROUP BY l.Logger_ID
I get the expected, newest, result. However, I'm pretty sure the Logger_ID is not the one belonging to that TimeOfLog.
Why is that/What am I misunderstanding here?
To get the maximum row, don't think group by; think filtering. Here is one method:
select l.*
from log l
where l.timeoflog = (select max(t2.timeoflog)
from log l2
where l2.logger_id = l.logger_id
);
If you just want the maximum time, then aggregation is appropriate:
select logger_id, max(timeoflog)
from log l
group by logger_id;
You have the expression:
HAVING MAX(l.TimeOfLog)
This just checks that the maximum is not 0 or NULL.
You are misunderstarding how GROUP BY AND HAVING works.
GROUP BY groups all rows that have same values in columns specified columns together into one group. If you select one column that is not mentioned in GROUP BY without using agregate function, you will randomly get one value from the grouped rows.
If you use agregate function like MAX() then the function is applied on all grouped rows and then result is selected.
HAVING is a filter similar to WHERE but while WHERE is applied before grouping the HAVING filter is applied after grouping.
You can use aggregate functions there. The correct usage of having might be for example
SELECT column,
FROM table
GROUP BY column
HAVING COUNT(*) > 1
This query would only select values of column that are present more than once.
In your example the MAX(c.TimeOfLog) will always be true as long as c.TimeOfLog is not empty for at least one row in group so it won't filter anything.

How to merge this two query statement into one query statement

1. SELECT * FROM instalmentsdetails WHERE instalmentName='Third Installment'AND studentFeeId='1'
2. select max(`receiptNo`)as `receiptNo` FROM instalmentsdetails
Table instalmentsdetails
instalmentsDetailsId
studentFeeId
receiptNo
instalmentName
amount
dueDate
fineAmt
waivedAmt
scholarShip
grandTotal
status
Little confused .How to merge this two query statement into one query statement
P.S: One statement checks for the condition and the other checks for the max of receiptNo in that table
I want both the values in one query
Is this what you want?
SELECT max(`receiptNo`) as `receiptNo`
FROM instalmentsdetails
WHERE instalmentName='Third Installment' AND studentFeeId='1'
Update: how about this:
SELECT *
FROM instalmentsdetails as inds
INNER JOIN (
SELECT max(`receiptNo`) as `maxreceiptNo`
FROM instalmentsdetails
) as maxt
WHERE inds.instalmentName='Third Installment' AND inds.studentFeeId='1'
This applies the filter to the table, then adds an extra column (the maximum receiptNo)
Assuming the goal is to get:
a list of instalmentsdetails with specific a instalmentName and studentFeeId
global maximum
 
SELECT *, 0 AS receiptNo FROM instalmentsdetails WHERE instalmentName='Third Installment'AND studentFeeId='1'
UNION
select *, max(`receiptNo`) as `receiptNo` FROM instalmentsdetails
Update
Apparently the OP simply wants to consolidate separate query results into a single row. In that case:
SELECT
*,
(SELECT max(`receiptNo`) FROM instalmentsdetails) AS maxReceiptNo
FROM instalmentsdetails WHERE instalmentName='Third Installment'AND studentFeeId='1'
From all the reading, Matt is correct, but maybe I can help explain what he's doing...
The first part of the query (From InstalmentsDetails WHERE YourCondition) will get all records that qualify for the condition.
THEN, by doing a JOIN to the second query (select max( 'receiptNo' ) from... with no where clause ) will ALWAYS return a single row, single column of the maximum receipt without regard to ANY criteria.
This creates an implied Cartesian result. Join everything in the first table with every record in the second. Since there is no explicit join condition, every row will get the same "max()" value as a returned column. And since there will only be one record in the select max() call, you never worry about duplicates.
Now, if you wanted the maximum receipt within the same criteria, you would just copy that same criteria to the select max() query portion.