SQL - pull unique name with the lastest date and lowest value - sql

how do i get unique name with the latest date and lowest value.
Name date value
brad 1/2/10 1.1
brad 1/2/10 2.3
bob 1/6/10 1.0
brad 2/4/09 13.2
this query does not seem to work
SELECT distinct
A.[ViralLoadMemberID]
,B.LastName
,B.FirstName
,A.[Date]
,A.[vaule]
FROM [t].[dbo].[tblViralLoad] A
left join [dbo].[tblEnrollees] B on A.ViralLoadMemberID = B.MemberID
where
A.Date =
(
select MAX(Date)
from dbo.tblViralLoad
where ViralLoadMemberID = A.ViralLoadMemberID
and
( Date >= '07/01/2014'
and Date <= '12/3/2014' ) )

The idea is to use order by and fetch only one row. If you want the lowest value on the latest date, the standard SQL would be:
select t.*
from table t
order by desc desc, value asc
fetch first 1 row only;
For older versions of SQL Server, you would omit the last line and do select top 1 * . . .. For MySQL, the last line would be limit 1.

Fun with rank()
declare #t as table (name varchar(50),dte date,val decimal(18,10));
insert into #t(name,dte,val) values
('Dave','1/1/2015',1.0),
('Dave','1/3/2015',1.2),
('Dave','1/4/2015',1.5),
('Dave','1/10/2015',1.3),
('Dave','1/15/2015',1.2),
('Steve','1/11/2015',1.6),
('Steve','1/12/2015',1.1),
('Steve','1/15/2015',1.2),
('Bill','1/21/2015',1.9),
('Ted','1/1/2015',1.8),
('Ted','1/10/2015',1.0),
('Ted','1/12/2015',1.7)
-- This will show the lowest prices by each person
select name,dte,val from (select name,dte,val, rank() over (partition by name order by val) as r from #t) as data where r = 1
-- This will be users lowest price and the last day they sublitted a prices regurdless if it is the lowest
select name,max(dte) as [last Date] ,min(val) as [Lowest Value] from #t group by name
-- Who had the lowest price last regurdless if they have raised there price later.
select top(1) name,dte [last lowest quote],val from (select name,dte,val, rank() over (order by val) as r from #t) as data where r = 1 order by dte desc
-- what is the lowest price cueently quoted reguarless who quoted it
select top(1) name,dte [best active quote],val from (select name,dte,val, rank() over (partition by name order by dte desc) as r from #t) as data where r = 1 order by val

Related

How can I obtain the minimum date for a value that is equal to the maximum date?

I am trying to obtain the minimum start date for a query, in which the value is equal to its maximum date. So far, I'm able to obtain the value in it's maximum date, but I can't seem to obtain the minimum date where that value remains the same.
Here is what I got so far and the query result:
select a.id, a.end_date, a.value
from database1 as a
inner join (
select id, max(end_date) as end_date
from database1
group by id
) as b on a.id = b.id and a.end_date = b.end_date
where value is not null
order by id, end_date
This result obtains the most recent record, but I'm looking to obtain the most minimum end date record where the value remains the same as the most recent.
In the following sample table, this is the record I'd like to obtain the record from the row where id = 3, as it has the minimum end date in which the value remains the same:
id
end_date
value
1
02/12/22
5
2
02/13/22
5
3
02/14/22
4
4
02/15/22
4
Another option that just approaches the problem somewhat as described for the sample data as shown - Get the value of the maximum date and then the minimum id row that has that value:
select top(1) t.*
from (
select top(1) Max(end_date)d, [value]
from t
group by [value]
order by d desc
)d
join t on t.[value] = d.[value]
order by t.id;
DB<>Fiddle
I'm most likely overthinking this as a Gaps & Island problem, but you can do:
select min(end_date) as first_date
from (
select *, sum(inc) over (order by end_date desc) as grp
from (
select *,
case when value <> lag(value) over (order by end_date desc) then 1 else 0 end as inc
from t
) x
) y
where grp = 0
Result:
first_date
----------
2022-02-14
See running example at SQL Fiddle.
with data as (
select *,
row_number() over (partition by value) as rn,
last_value(value) over (order by end_date) as lv
from T
)
select * from data
where value = lv and rn = 1
This isn't looking strictly for streaks of consecutive days. Any date that happened to have the same value as on final date would be in contention.

Select every second record then determine earliest date

I have table that looks like the following
I have to select every second record per PatientID that would give the following result (my last query returns this result)
I then have to select the record with the oldest date which would be the following (this is the end result I want)
What I have done so far: I have a CTE that gets all the data I need
WITH cte
AS
(
SELECT visit.PatientTreatmentVisitID, mat.PatientMatchID,pat.PatientID,visit.RegimenDate AS VisitDate,
ROW_NUMBER() OVER(PARTITION BY mat.PatientMatchID, pat.PatientID ORDER BY visit.VisitDate ASC) AS RowNumber
FROM tblPatient pat INNER JOIN tblPatientMatch mat ON mat.PatientID = pat.PatientID
LEFT JOIN tblPatientTreatmentVisit visit ON visit.PatientID = pat.PatientID
)
I then write a query against the CTE but so far I can only return the second row for each patientID
SELECT *
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate, RowNumber FROM cte
) as X
WHERE RowNumber = 2
How do I return the record with the oldest date only? Is there perhaps a MIN() function that I could be including somewhere?
If I follow you correctly, you can just order your existing resultset and retain the top row only.
In standard SQL, you would write this using a FETCH clause:
SELECT *
FROM (
SELECT
visit.PatientTreatmentVisitID,
mat.PatientMatchID,
pat.PatientID,
visit.RegimenDate AS VisitDate,
ROW_NUMBER() OVER(PARTITION BY mat.PatientMatchID, pat.PatientID ORDER BY visit.VisitDate ASC) AS rn
FROM tblPatient pat
INNER JOIN tblPatientMatch mat ON mat.PatientID = pat.PatientID
LEFT JOIN tblPatientTreatmentVisit visit ON visit.PatientID = pat.PatientID
) t
WHERE rn = 2
ORDER BY VisitDate
OFFSET 0 ROWS FETCH FIRST 1 ROW ONLY
This syntax is supported in Postgres, Oracle, SQL Server (and possibly other databases).
If you need to get oldest date from all selected dates (every second row for each patient ID) then you can try window function Min:
SELECT * FROM
(
SELECT *, MIN(VisitDate) OVER (Order By VisitDate) MinDate
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate,
RowNumber FROM cte
) as X
WHERE RowNumber = 2
) Y
WHERE VisitDate=MinDate
Or you can use SELECT TOP statement. The SELECT TOP clause allows you to limit the number of rows returned in a query result set:
SELECT TOP 1 PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate FROM
(
SELECT *
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate,
RowNumber FROM cte
) as X
WHERE RowNumber = 2
) Y
ORDER BY VisitDate
For simplicity add order desc on date column and use TOP to get the first row only
SELECT TOP 1 *
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate, RowNumber FROM cte
) as X
WHERE RowNumber = 2
order by VisitDate desc

How to retrieve MAX Turntime of Top Two earliest date?

How would I construct a query to receive the MAX TurnTime per ID of the first 2 rounds? Rounds being defined as minimum Beginning_Date to mininmum End_Date of an ID. Without reusing either of the dates for the second round Turn Time calculation.
You can use row_number() . . . twice:
select d.*
from (select d.*,
row_number() over (partition by id order by turn_time desc) as seqnum_turntime
from (select d.*,
row_number() over (partition by id order by beginning_end desc) as seqnum_round
from data d
) d
where seqnum_round <= 2
) d
where seqnum_turntime = 1;
The innermost subquery gets the first two rounds. The outer subquery gets the maximum.
You could express this without window functions as well:
select top (1) with ties d.*
from data d
where d.beginning_date <= (select d2.beginning_date
from data d2
where d2.id = d.id
offset 1 fetch first 1 row only
)
order by row_number() over (partition by id order by turntime desc);
SELECT
ID
,turn_time
,beginning_date
,end_date
FROM
(
SELECT
ID
,MAX(turn_time) OVER (PARTITION BY Id ORDER BY BeginningDate ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS turn_time --Maximum turn time of the current row and preceding row
,MIN(BeginningDate) OVER (PARTITION BY Id ORDER BY BeginningDate ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS beginning_date --Minimum begin date over current row and preceding row (could also use LAG)
,end_date
,ROW_NUMBER() OVER (PARTITION BY Id ORDER BY BeginningDate) AS Turn_Number
FROM
<whatever your table is>
) turn_summary
WHERE
Turn_Number = 2

Per year one maximum date row according to previous row date

I have a table having two columns and I want to fetch data of 6 years with rules
The first row would be maximum date row that is available before and equals to input date (I will pass an input date)
From the second row till 6th row I need maximum(date row) that is earlier than previous row data selected data and there should not be 2 rows for same year i need only latest one according to the previous row but not in same year.
declare #tbl table (id int identity, marketdate date )
insert into #tbl (marketdate)
values('2018-05-31'),
('2017-06-01'),
('2017-05-28'),
('2017-04-28'),
('2016-05-26'),
('2015-04-18'),
('2015-04-20'),
('2015-03-18'),
('2014-05-31'),
('2014-04-18'),
('2013-04-15')
output:
id marketdate
1 2018.05.31
3 2017.05.28
5 2016.05.27
7 2015.04.20
9 2014.04.18
10 2013.04.15
Can't you do this with a simple order by/desc?
SELECT TOP 6 id, max(marketdate) FROM tbl
WHERE tbl.marketdate <= #date
GROUP BY YEAR(marketdate), id, marketdate
ORDER BY YEAR(marketdate) DESC
Based purely on your "Output" given your sample data, I believe the following is what you are after (The max date for each distinct year of data):
SELECT TOP 6
max(marketdate),
Year(marketDate) as marketyear
FROM #tbl
WHERE #tbl.marketdate <= getdate()
GROUP BY YEAR(marketdate)
ORDER BY YEAR(marketdate) DESC;
SQLFiddle of this matching your output
you can use row_number if you are using sql server
select top 6
id
, t.marketdate
from ( select rn = row_number() over (partition by year(marketdate)order by marketdate desc)
, id
, marketdate
from #tbl) as t
where t.rn = 1
order by t.marketdate desc
The following recursively searches for the next date, which must be at least one year earlier than the previous date.
Your parameterised start position goes where I chose 2018-06-01.
WITH
recursiveSearch AS
(
SELECT
id,
marketDate
FROM
(
SELECT
yourTable.id,
yourTable.marketDate,
ROW_NUMBER() OVER (ORDER BY yourTable.marketDate DESC) AS relative_position
FROM
yourTable
WHERE
yourTable.marketDate <= '2018-06-01'
)
search
WHERE
relative_position = 1
UNION ALL
SELECT
id,
marketDate
FROM
(
SELECT
yourTable.id,
yourTable.marketDate,
ROW_NUMBER() OVER (ORDER BY yourTable.marketDate DESC) AS relative_position
FROM
yourTable
INNER JOIN
recursiveSearch
ON yourTable.marketDate < DATEADD(YEAR, -1, recursiveSearch.marketDate)
)
search
WHERE
relative_position = 1
)
SELECT
*
FROM
recursiveSearch
WHERE
id IS NOT NULL
ORDER BY
recursiveSearch.marketDate DESC
OPTION
(MAXRECURSION 0)
http://sqlfiddle.com/#!18/56246/13

How to select max rownumber for each partition in SQL Server

Can anybody tell me how to select the max row number for each partition in SQL Server using CTE.
Suppose any employee is having 4 transaction rows and another is having only one row then how to select max rows for those employees.
I am having job table I want to fetch max row number for employee to fetch the latest transaction for that employee
I'd tried following
With CTE as (
Select
My fields,
Rownum = row_number() over(partition by emplid order by date) from jobtable
Where
Myconditions
)
Select * from CTE B left outer join
CTE A on A.emplid = B.emplid
Where
A.rownum = (select max(a2.rownum) from jobtable a2)
Do left join is required above or it is not at all needed ?
Please tell me how to fetch rownum if only 1 row exist for any employees as above query is fetching only employees which are having.greatest rownum in whole table
With CTE as (
Select
My fields,
Rownum = row_number() over(partition by emplid order by date DESC)
from jobtable
Where
Myconditions
)
SELECT *
FROM
cte
WHERE
RowNum = 1
Just reverse the order of your ROW_NUMBER and and select where it equals 1. Row numbers can be ascending (ASC) or descending (DESC). So if you want the most recent date to get the latest record ORDER BY date DESC, if you want the earliest record first you would choose ORDER BY date ASC (or date)