SQL select max(date) and corresponding value [duplicate] - sql

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to get the record of a table who contains the maximum value?
I've got an aggregate query like the following:
SELECT TrainingID, Max(CompletedDate) as CompletedDate, Max(Notes) as Notes --This will only return the longest notes entry
FROM HR_EmployeeTrainings ET
WHERE (ET.AvantiRecID IS NULL OR ET.AvantiRecID = #avantiRecID)
GROUP BY AvantiRecID, TrainingID
Which is working, and returns correct data most of the time, but I noticed a problem. The Notes field which gets returned will not necessarily match the record that the max(completedDate) is from. Instead it will be the one with the longest string? Or the one with the highest ASCII value? What does SQL Server do in the event of a tie between two records? I'm not even sure. What I want to get is the notes field from the max(completedDate) record. How should I got about doing this?

You can use a subquery. The subquery will get the Max(CompletedDate). You then take this value and join on your table again to retrieve the note associate with that date:
select ET1.TrainingID,
ET1.CompletedDate,
ET1.Notes
from HR_EmployeeTrainings ET1
inner join
(
select Max(CompletedDate) CompletedDate, TrainingID
from HR_EmployeeTrainings
--where AvantiRecID IS NULL OR AvantiRecID = #avantiRecID
group by TrainingID
) ET2
on ET1.TrainingID = ET2.TrainingID
and ET1.CompletedDate = ET2.CompletedDate
where ET1.AvantiRecID IS NULL OR ET1.AvantiRecID = #avantiRecID

Ah yes, that is how it is intended in SQL. You get the Max of every column seperately. It seems like you want to return values from the row with the max date, so you have to select the row with the max date. I prefer to do this with a subselect, as the queries keep compact easy to read.
SELECT TrainingID, CompletedDate, Notes
FROM HR_EmployeeTrainings ET
WHERE (ET.AvantiRecID IS NULL OR ET.AvantiRecID = #avantiRecID)
AND CompletedDate in
(Select Max(CompletedDate) from HR_EmployeeTrainings B
where B.TrainingID = ET.TrainingID)
If you also want to match by AntiRecID you should include that in the subselect as well.

Each MAX function is evaluated individually. So MAX(CompletedDate) will return the value of the latest CompletedDate column and MAX(Notes) will return the maximum (i.e. alphabeticaly highest) value.
You need to structure your query differently to get what you want. This question had actually already been asked and answered several times, so I won't repeat it:
How to find the record in a table that contains the maximum value?
Finding the record with maximum value in SQL

There's no easy way to do this, but something like this will work:
SELECT ET.TrainingID,
ET.CompletedDate,
ET.Notes
FROM
HR_EmployeeTrainings ET
inner join
(
select TrainingID, Max(CompletedDate) as CompletedDate
FROM HR_EmployeeTrainings
WHERE (ET.AvantiRecID IS NULL OR ET.AvantiRecID = #avantiRecID)
GROUP BY AvantiRecID, TrainingID
) ET2
on ET.TrainingID = ET2.TrainingID
and ET.CompletedDate = ET2.CompletedDate

Related

SQL - Returning fields based on where clause then joining same table to return max value?

I have a table named Ticket Numbers, which (for this example) contain the columns:
Ticket_Number
Assigned_Group
Assigned_Group_Sequence_No
Reported_Date
Each ticket number could contain 4 rows, depending on how many times the ticket changed assigned groups. Some of these rows could contain an assigned group of "Desktop Support," but some may not. Here is an example:
Example of raw data
What I am trying to accomplish is to get the an output that contains any ticket numbers that contain 'Desktop Support', but also the assigned group of the max sequence number. Here is what I am trying to accomplish with SQL:
Queried Data
I'm trying to use SQL with the following query but have no clue what I'm doing wrong:
select ih.incident_number,ih.assigned_group, incident_history2.maxseq, incident_history2.assigned_group
from incident_history_public as ih
left join
(
select max(assigned_group_seq_no) maxseq, incident_number, assigned_group
from incident_history_public
group by incident_number, assigned_group
) incident_history2
on ih.incident_number = incident_history2.incident_number
and ih.assigned_group_seq_no = incident_history2.maxseq
where ih.ASSIGNED_GROUP LIKE '%DS%'
Does anyone know what I am doing wrong?
You might want to create a proper alias for incident_history. e.g.
from incident_history as incident_history1
and
on incident_history1.ticket_number = incident_history2.ticket_number
and incident_history1.assigned_group_seq_no = incident_history2.maxseq
In my humble opinion a first error could be that I don't see any column named "incident_history2.assigned_group".
I would try to use common table expression, to get only ticket number that contains "Desktop_support":
WITH desktop as (
SELECT distinct Ticket_Number
FROM incident_history
WHERE Assigned_Group = "Desktop Support"
),
Than an Inner Join of the result with your inner table to get ticket number and maxSeq, so in a second moment you can get also the "MAXGroup":
WITH tmp AS (
SELECT i2.Ticket_Number, i2.maxseq
FROM desktop D inner join
(SELECT Ticket_number, max(assigned_group_seq_no) as maxseq
FROM incident_history
GROUP BY ticket_number) as i2
ON D.Ticket_Number = i2.Ticket_Number
)
SELECT i.Ticket_Number, i.Assigned_Group as MAX_Group, T.maxseq, i.Reported_Date
FROM tmp T inner join incident_history i
ON T.Ticket_Number = i.Ticket_Number and i.assigned_group_seq_no = T.maxseq
I think there are several different method to resolve this question, but I really hope it's helpful for you!
For more information about Common Table Expression: https://www.essentialsql.com/introduction-common-table-expressions-ctes/

SQL: how to get value based upon value earlier in query

See code below. The itemdescription I want to get back depends on the value from itemcode. The value returned by max(itemcode) should be matched to the right itemdescription.
New to SQL and willing to learn :)
select ordernumber
, max(quantity)
, max(itemcode)
, max(itemdescription)
from salesorderlines
group by ordernumber;
Presumably, you want the rows from salesorderlines that have the maximum quantity for each orderdid (that is my best guess of a reasonable question that your query would attempt to answer).
If so, think "filtering", not "aggregation":
select sol.*
from salesorderlines sol
where sol.quantity = (select max(sol2.quantity)
from salesorderlines sol2
where sol2.quantity = sol.quantity
);

SQL Statement to select row where previous row status = 'C' AS400

This is being run on sql for IBMI Series 7
I have a table which stores info about orders. Each row has an order number (ON), part number(PN), and sequence number(SEQ). Each ON will have multiple PN's linked to them and each part number has multiple SEQ Number. Each sequence number represents the order in which to do work on the part. Somewhere else in the system once the part is at a location and ready to be worked on it shows a flag. What I want to do is get a list of orders for a location that have not yet arrived but have been closed out on the previous location( Which means the part is on it's way).
I have a query listed below that I believe should work but I get the following error: "The column qualifier or table t undefined". Where is my issue at?
Select * From (SELECT M2ON as Order__Number , M2SEQ as Sequence__Number,
M2PN as Product__Number,ML2OQ as Order__Quantity
FROM M2P
WHERE M2pN in (select R1PN FROM R1P WHERE (RTWC = '7411') AND (R1SEQ = M2SEQ)
)
AND M2ON IN (SELECT M1ON FROM M1P WHERE ML1RCF = '')
ORDER BY ML2OSM ASC) as T
WHERE
T.Order__Number in (Select t3.m2on from (SELECT *
FROM(Select * from m2p
where m2on = t.Order__Number and m2pn = t.Product__Number
order by m2seq asc fetch first 2 rows only
)as t1 order by m2seq asc fetch first row only
) as t3 where t3.m2stat = 'C')
EDIT- Answer for anyone else with this issue
Clutton's Answer worked with slight modification so thank you to him for the fast response! I had to name my outer table and specify that in the subquery otherwise the as400 would kick back and tell me it couldn't find the columns. I also had to order by the sequence number descending so that I grabbed the highest record that was below the parameter(otherwise for example if my sequence number was 20 it could grab 5 even though 10 was available and should be shown first. Here is the subquery I now use. Please note the actual query names m2p as T1.
IFNULL((
SELECT
M2STAT
FROM
M2P as M2P_1
WHERE
M2ON = T1.M2ON
AND M2SEQ < T1.M2SEQ
AND M2PN IN (select R1PN FROM R1P WHERE (RTWC = #WC) AND (R1SEQ = T1.M2SEQ))
ORDER BY M2SEQ DESC
FETCH FIRST ROW ONLY
), 'NULL') as PRIOR_M2STAT
Just reading your question, it looks like something I do frequently to emulate RPG READPE op codes. Is the key to M2P Order/Seq? If so, here is a basic piece that may help you build out the rest of the query.
I am assuming that you are trying to get the prior record by key using SQL. In RPG this would be like doing a READPE on the key for a file with Order/Seq key.
Here is an example using a subquery to get the status field of the prior record.
SELECT
M2ON, M2PN, M2OQ, M2STAT,
IFNULL((
SELECT
M2STAT
FROM
M2P as M2P_1
WHERE
M2P_1.M2ON = M2ON
AND M2P_1.M2SEQ < M2SEQ
FETCH FIRST ROW ONLY
), '') as PRIOR_M2STAT
FROM
M2P
Note that this wraps the subquery in an IFNULL to handle the case where it is the first sequence number and no prior sequence exists.

Get Only One Row For Each ID With the Highest Value

I have a query
SELECT
*
FROM
mgr.MF_AGREEMENT_LGR TABLE1
INNER JOIN
(SELECT
MAX(VALUE_DATE) AS VALUE_DATE,
REGISTRATION_NO AS REGISTRATION_NO
FROM
mgr.MF_AGREEMENT_LGR
GROUP BY
REGISTRATION_NO) AS TABLE2 ON TABLE1.REGISTRATION_NO = TABLE2.REGISTRATION_NO
WHERE
TABLE1.VALUE_DATE = TABLE2.VALUE_DATE
AND TABLE1.TRX_CODE = 'LCLR'
ORDER BY
TABLE1.REGISTRATION_NO
This returns the rows with the latest date for each REGISTRATION_CODE. Some have like three or more results for each REGISTRATION_CODE because it has more than one transaction on the same date.
Also, each row has its DOC_NO field.
My question is, how am I going to get only one row from each REGISTRATION_CODE with the highest DOC_NO.
By the way, DOC_NO is a varchar.
Example value for this field is: Amort 1, Amort 12, Amort 5
If those examples are in one REGISTRATION_CODE, I only need the row with the highest amort which is Amort 12.
I am using a SQL Server 2000.
SQL Server 2000 has not been supported in years. You really should upgrade to supported software.
You can get what you want with not exists:
SELECT al.*
FROM mgr.MF_AGREEMENT_LGR al
WHERE NOT EXISTS (SELECT 1
FROM mgr.MF_AGREEMENT_LGR al2
WHERE al2.registration_no = al.registration_no and
(al2.date > al2.date or
al2.date = al.date and al2.DOC_NO > al.DOC_NO
)
) AND
al.TRX_CODE = 'LCLR';
You probably want the condition on 'LCLR' in the subquery as well. However, that is not in your original query, so I'm leaving it out.

Can change select clause when input is null?

I want to do a select in a table named ALBARANES that it's going to show me all
the columns of the table. This select has inputs values to do the where clauses.
Inputs: #serie, #client
What I want is: If #serie's value is null then show me all the columns regardles of the column value of ALBARANES.SERIE, but if #serie has a value not null then do a clause using it.
SELECT * FROM ALBARANES AC
WHERE
AC.SERIE = #serie/*Code when #serie has value not null*/
AC.FECHA < (SELECT CAST ('Now' as date) from RDB$DATABASE)
And the same with the input #client. How can I implement this select?
You want:
WHERE (AC.SERIE = #serie or #serie is null) and
ac.fecha < date(now())
Your question is tagged MySQL. However, your date logic is not MySQL, so I changed it. If your question is mistagged, then you may want your original logic.