SQL-find the ratings with the max complete_date with group by - sql

Please run the DDL and DML on sqlfiddle. I am trying to come up with a query to find the ratings of the FID that has the max complete_date
DDL:
create table crr (rating varchar(255), FID int, complete_date varchar(255));
DML:
insert into crr values ('low', 182, '2021/11/1'),('medium', 182,'2022/6/14'), ('medium', 369,'2021/9/1')
, ('medium', 369,'2021/11/9'), ('medium', 429,'2021/4/5'), ('medium', 429,'2021/4/6'),('high', 429,'2022/12/5');
my query is:
Select c.fid, rating, c.complete_date
From crr c
Inner Join (
Select fid, Max(complete_date)as d
From crr
Group By fid)A;
On c.fid=A.fid and c.complete_date=d;
It is not returning what I wanted.
Ideal output would be:
rating FID complete_date
medium 182 2022/6/14
medium 369 2021/11/9
high 429 2022/12/5
It should be easy-peasy, please advise.

Is that what you are looking for?
select * from crr a
where complete_date = (select max(complete_date) from crr b where b.fid=a.fid)
order by fid
I changed completed_date to date, with varchar I was having different results
create table crr (rating varchar(255), FID int, complete_date date);
insert into crr values ('low', 182, '2021/11/1'),('medium', 182,'2022/6/14'), ('medium', 369,'2021/9/1')
, ('medium', 369,'2021/11/9'), ('medium', 429,'2021/4/5'), ('medium', 429,'2021/4/6'),('high', 429,'2022/12/5');

Select rating, c.fid, c.complete_date
From crr c
Inner Join (
Select fid, Max(complete_date) as d
From crr
Group By fid) as A On c.fid=A.fid and c.complete_date=A.d;
Date is a string, then sorting will be in lexicographic order

Come to think of it.
This is what I came up with
select rating, fid, complete_date from (
select *, row_number() over(partition by FID order by complete_date desc)as n
from crr)A
where A.n=1

Related

How to query latest records in SQL Server

I've tried to to use similar asks but still not able to get my desired result. Here is three sample records.
create table #temps
(
airport varchar(10),
country varchar(10),
plane varchar(10),
id int,
flight_date datetime
)
insert into #temps
values ('IAD', 'USA', 'a777', '195', ' 7/26/2022 11:39:00 AM')
insert into #temps
values ('IAD', 'USA', 'a777', '195', ' 8/12/2022 9:51:00 AM')
insert into #temps
values ('BOS', 'USA', 'a777', '195', ' 8/12/2022 9:51:00 AM')
I tried to retrieve the latest record which is from BOS airport (discard the impossible of the same flight dates occurred from different airports)
I used the ROW_NUMBER such as below and and wanted to return the max rank = 3.
SELECT DISTINCT
a.airport, a.country, a.flight_date, a.plane, id,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY flight_date ASC) AS Ct
FROM
#temps a
I also tried the max such as
SELECT A.airport, A.id, A.flight_date, A.country
FROM #temps A
INNER JOIN (SELECT id, MAX(flight_date) as MAX_FLIGHT_DATE
FROM #temps
GROUP BY id) B ON (A.flight_date = B.MAX_FLIGHT_DATE)
Is there a better technique that can return the record from BOS airport?
Thanks!
joe
You could use ORDER by.
SELECT TOP(3) airport,
country,
plane,
id,
flight_date
FROM #temps
ORDER BY flight_date DESC;

max with distinct in sql

I have a table with rows/data in the following structure
picture
I want a query that results in the red line(max credit no)
I have tried these:
SELECT employee no, MAX(credit no)
FROM mytable
GROUP BY employee no
SELECT distinct employee no, MAX(credit no)
FROM mytable
GROUP BY employee no
but it doesn't give me the red line records
You can use correlated subquery :
select mt.*
from mytable mt
where mt.creditno = (select max(mt1.creditno)
from mytable mt1
where mt1.employeeno = mt.employeeno
);
You sould use group by and order by clouse. if you want to just top 2 employee_no, write to select top 2
select employee_no, max(credit_no) as max_credit_no from yourtable group by employee_no order by max_credit_no desc
select top 2, employee_no, max(credit_no) as max_credit_no from yourtable group by employee_no order by max_credit_no desc
if I understand correctly, I would use the line number to sort the values in descending order then select the lines.
CREATE TABLE #data
(
employee_no int,
credit_no int,
stat nvarchar(3)
)
INSERT INTO #data
(employee_no, credit_no, stat)
VALUES
(100022, 244, 'ret'),
(100022, 245, 'emp'),
(100023, 244, 'vac'),
(100023, 245, 'ret'),
(100023, 246, 'emp')*/
And select:
select *
from (
select employee_no,
credit_no,
stat,
ROW_NUMBER() over (partition by employee_no order by credit_no desc) id
from #data
)x
where id = 1
And result:
https://dbfiddle.uk/?rdbms=sqlserver_2016&fiddle=2b97f6e553231a6a9524b143e730f323

Select the newest record

I would like to run a select statement that runs and select only the newest record by Recored_timestampe field for the keys teacher_id and student_id. So any time, it runs it needs to provide only one record. how could I do it, please? The output could be without the field Recored_timestampe. Thanks
Using the window function,partitioned by teacher_id and student_id and sorting it by recorded_timestamp will give you the desired result.
select * from(select teacher_id,student_id,teacher_name,comment ,recorded_timestamp, row_number() over(partition by teacher_id,student_id order by recorded_timestamp desc)as rownum from temp0607)out1 where rownum=1
Also you may have to look at the way recorded_timestamp is stored. If it is stored as string, you can convert it into timestamp using from_unixtime(unix_timestamp(recorded_timestamp,'dd/MM/yyyy HH:mm'),'dd/MM/yyyy HH:mm')
First, arrange the record by datetime
SELECT *,RANK() OVER (PARTITION BY student_id ORDER BY Recored_timestamp desc) as ranking
FROM #temp
Then, if you want to know the newest record with student_id which is not null, then you can use OUTER APPLY to add a column which is non-NULL student_id.
OUTER APPLY (SELECT student_id
FROM #temp
WHERE #temp.teacher_id = ranktable.teacher_id
AND student_id IS NOT NULL
) AS jointable
Here is an example:
Create Table #temp
(
teacher_id int
,student_id int
,teacher_name varchar(40)
,comment varchar(100)
,Recored_timestamp datetime
)
INSERT INTO #temp
VALUES
(449,111,'lucy','Could be better','2021-05-04 07:00:00.000')
,(449,null,'lucy','smily','2021-05-11 07:00:00.000')
,(449,111,'lucy','not listening','2021-05-08 07:00:00.000')
,(448,null,'Toni','Good','2021-06-04 09:00:00.000')
,(448,222,'Toni','not doing as expected','2021-06-04 08:00:00.000')
SELECT DISTINCT teacher_id,
jointable.student_id,
teacher_name,
comment,
Recored_timestamp,
ranking
FROM
(
SELECT *,RANK() OVER (PARTITION BY teacher_id ORDER BY Recored_timestamp DESC) AS ranking
FROM #temp
) AS ranktable
OUTER APPLY (SELECT student_id
FROM #temp
WHERE #temp.teacher_id = ranktable.teacher_id
AND student_id IS NOT NULL
) AS jointable
WHERE ranking = 1 --only newest record will be extracted
Drop table #temp
You can base from this query to get the newest data.
SELECT TOP 1 * FROM tablename T1
INNER JOIN(SELECT teacher_id, Max(Recored_timestamp) as MaxDate from tablename GROUP BY teacher_id) T2 ON T2.teacher_id = T1.teacher_id AND T1.Recored_timestamp = T2.MaxDate

Get the Recent changed value from History Table

I have a history table with the following values
CREATE TABLE History (SnapShotDate DATETIME, UID VARCHAR(10), DUEDATE DATETIME)
INSERT INTO History VALUES ('03-23-2015','PT-01','2015-04-22')
INSERT INTO History VALUES ('03-30-2015','PT-01','2015-04-20')
INSERT INTO History VALUES ('04-06-2015','PT-01','2015-06-30')
INSERT INTO History VALUES ('03-23-2015','PT-02','2015-04-22')
INSERT INTO History VALUES ('03-30-2015','PT-02','2015-04-22')
INSERT INTO History VALUES ('04-06-2015','PT-02','2015-04-22')
INSERT INTO History VALUES ('03-23-2015','PT-03','2015-04-18')
INSERT INTO History VALUES ('03-30-2015','PT-03','2015-04-22')
INSERT INTO History VALUES ('04-06-2015','PT-03','2015-04-22')
I need an output in the below format. I need the most recent changed value for any given UID. Please help me in getting the below result
OUTPUT
UID PreviousDueDate CurrentDueDate
----------------------------------------
PT-01 2015-04-20 2015-06-30
PT-02 2015-04-22 2015-04-22
PT-03 2015-04-18 2015-04-22
Thanks
You can try with this SQL:
select UID,date_format(min(DUEDATE), '%Y-%m-%d') as PreviousDueDate,date_format(max(DUEDATE), '%Y-%m-%d') as CurrentDueDate from History group by UID;
I've never used the LAG function before so but seems super easy!!!
; WITH CTE AS (
SELECT UID,
LAG(DUEDATE,1,NULL) OVER (PARTITION BY UID ORDER BY SnapShotDate ASC) AS PreviousDueDate,
DUEDATE AS CurrentDueDate,
ROW_NUMBER() OVER (PARTITION BY UID ORDER BY SnapShotDate DESC) AS RowNumber
FROM History
)
SELECT UID, PreviousDueDate, CurrentDueDate
FROM CTE
WHERE ROWNUMBER = 1
Here is the fiddle.
You should use Convert function in sql server.
SELECT A.UID
,CONVERT(varchar(10),B.DUEDATE, 20) as PreviousDueDate
,CONVERT(varchar(10),A.DUEDATE, 20) as CurrentDueDate
FROM
(
SELECT *,row_number() OVER( PARTITION BY UID ORDER BY SnapShotDate DESC) AS ROWID
FROM History
)A
LEFT JOIN
(
SELECT *,row_number() OVER( PARTITION BY UID ORDER BY SnapShotDate DESC) AS ROWID
FROM History
)B ON A.UID=B.UID AND B.ROWID=2
WHERE A.ROWID=1
GROUP BY A.UID,A.DUEDATE,B.DUEDATE
Output:
UID PreviousDueDate CurrentDueDate
PT-01 2015-04-20 2015-06-30
PT-02 2015-04-22 2015-04-22
PT-03 2015-04-22 2015-04-22
PT-04 2015-04-22 2015-04-18
SELECT UID,
(SELECT DUEDATE FROM History WHERE SnapShotDate=(SELECT MIN(SnapShotDate) FROM History h2 WHERE h2.UID=h1.UID) )AS PreviousDueDate
(SELECT DUEDATE FROM History WHERE SnapShotDate=(SELECT MAX(SnapShotDate) FROM History WHERE h2.UID=h1.UID) )AS CurrentDueDate
FROM History h1
GROUP BY UID
SELECT UID,
(SELECT MIN(DUEDATE) FROM History HS WHERE HS.UID = H.UID GROUP BY UID )AS PreviousDueDate,
(SELECT Max(DUEDATE) FROM History HS WHERE HS.UID = H.UID GROUP BY UID )AS CurrentDueDate
FROM History H
GROUP BY UID

select the latest result based on DateTime field

I have a simple table with only 4 fields.
http://sqlfiddle.com/#!3/06d7d/1
CREATE TABLE Assessment (
id INTEGER IDENTITY(1,1) PRIMARY KEY,
personId INTEGER NOT NULL,
dateTaken DATETIME,
outcomeLevel VARCHAR(2)
)
INSERT INTO Assessment (personId, dateTaken, outcomeLevel)
VALUES (1, '2014-04-01', 'L1')
INSERT INTO Assessment (personId, dateTaken, outcomeLevel)
VALUES (1, '2014-04-05', 'L2')
INSERT INTO Assessment (personId, dateTaken, outcomeLevel)
VALUES (2, '2014-04-03', 'E3')
INSERT INTO Assessment (personId, dateTaken, outcomeLevel)
VALUES (2, '2014-04-07', 'L1')
I am trying to select for each "personId" their latest assessment result based on the dateTaken.
So my desired output for the following data would be.
[personId, outcomeLevel]
[1, L2]
[2, L1]
Thanks,
Danny
Try this:
;with cte as
(select personId pid, max(dateTaken) maxdate
from assessment
group by personId)
select personId, outcomeLevel
from assessment a
inner join cte c on a.personId = c.pid
where c.maxdate = a.dateTaken
order by a.personId
;with Cte as (Select personId,outcomeLevel, C= ROW_NUMBER()
over(PARTITION By personId Order By dateTaken desc)
From #Assessment
)
Select * from cte where C=1
Sample here
SELECT asst.personId,
asst.outcomeLevel
FROM dbo.Assessment asst
WHERE asst.dateTaken=(SELECT MAX(ast.dateTaken)
FROM assessment ast
WHERE asst.personid=ast.personId)
ORDER BY asst.personId
Result will be like this
personId outcomeLevel
1 L2
2 L1
Here is a possible solution using common table expression:
WITH cte AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY personId ORDER BY dateTaken DESC) AS rn
, personId
, outcomeLevel
FROM
[dbo].[Assessment]
)
SELECT
personId
, outcomeLevel
FROM
cte
WHERE
rn = 1
About CTEs
A common table expression (CTE) can be thought of as a temporary result set that is defined within the execution scope of a single SELECT, INSERT, UPDATE, DELETE, or CREATE VIEW statement. A CTE is similar to a derived table in that it is not stored as an object and lasts only for the duration of the query. Unlike a derived table, a CTE can be self-referencing and can be referenced multiple times in the same query. From MSDN: Using Common Table Expressions
try this:
SELECT a.personId, a.outcomeLevel
FROM Assessment a
INNER JOIN
(
SELECT max(dateTaken) as datetaken1, personId
FROM Assessment
GROUP BY personId ) b
ON a.dateTaken = b.datetaken1
demo: http://sqlfiddle.com/#!3/06d7d/9
Idea is to first derive a table with the max dates per person and then join that with the original table on the date field so you can get the outcome level for this maxed date...
This should work perfectly without cte :
SELECT [Table4].[personId], [Table4].[outcomeLevel]
FROM (
SELECT [Table1].[personId]
FROM [Assessment] AS [Table1]
GROUP BY [Table1].[personId]
) AS [Table2]
CROSS APPLY (
SELECT TOP (1) [Table3].[personId], [Table3].[outcomeLevel], [Table3].[dateTaken]
FROM [Assessment] AS [Table3]
WHERE [Table2].[personId] = [Table3].[personId]
ORDER BY [Table3].[dateTaken] DESC
) AS [Table4]
ORDER BY [Table4].[dateTaken] DESC