How to pick Max value of SQL Output - sql

SQL Query Syntax issue. I have a query which returns around 150,000 rows of records. In this query, you can see ROW_NUMBER() OVER PARTITION. On select * from cte, I need to pick only the highest value of ROW_NUMBER() for each Pat_id.
If RowNumber is 150 for one pat_id. I need only that row of records. I am having difficult in narrowing down to one record. I request experts to share your syntax to help me.
with cte
as (
select pat.pat_id,
pat.fname as [FirstName],
pat.mname as [MiddleName],
pat.lname as [LastName],
[DOB] =Convert(VARCHAR(12),pat.birth_date,101),
csc.name as [AccountType],
[Plan Name] = CASE when (isnull(org.name,'')='') then 'CASH' else org.name end
,cprx_disp.disp_days_supply
,cprx_disp.dispense_date
,(cprx_disp.dispense_date + cprx_disp.disp_days_supply) as [DateDue]
,ROW_NUMBER() over(PARTITION BY pat.pat_id ORDER BY cprx_disp.dispense_date) as [RowNumber]
From cppat pat (nolock)
left outer join cppat_ins patins(NoLock) ON patins.pat_id = pat.pat_id
left outer join csorg org on org.org_id = patins.org_id
inner join csct_code csc on pat.pat_type_cn = csc.code_num
join cprx on cprx.pat_id = pat.pat_id
join cprx_disp (nolock) on cprx.last_rxdisp_id = cprx_disp.rxdisp_id
where csc.ct_id = 163
and csc.code_num in (1033,1010,1011,1012,1016,1017,1016,1018)
and patins.status_cn = 1
and patins.priority = 1
-- Commented.
-- and pat.pat_id = 2561
)
select cte.[FirstName],
cte.[MiddleName],
cte.[LastName],
cte.[DOB],
cte.[AccountType],
cte.[Plan Name],
Cte.DateDue
from cte

Well, you're not actually using the RowNumber in the output, so I would just reverse it and then return those that equal 1:
with cte
as (
select pat.pat_id,
pat.fname as [FirstName],
pat.mname as [MiddleName],
pat.lname as [LastName],
[DOB] =Convert(VARCHAR(12),pat.birth_date,101),
csc.name as [AccountType],
[Plan Name] = CASE when (isnull(org.name,'')='') then 'CASH' else org.name end
,cprx_disp.disp_days_supply
,cprx_disp.dispense_date
,(cprx_disp.dispense_date + cprx_disp.disp_days_supply) as [DateDue]
,ROW_NUMBER() over(PARTITION BY pat.pat_id ORDER BY cprx_disp.dispense_date DESC) as [RowNumber]
from cppat pat (nolock)
left outer join cppat_ins patins(NoLock) on patins.pat_id = pat.pat_id
left outer join csorg org on org.org_id = patins.org_id
inner join csct_code csc on pat.pat_type_cn = csc.code_num
join cprx on cprx.pat_id = pat.pat_id
join cprx_disp (nolock) on cprx.last_rxdisp_id = cprx_disp.rxdisp_id
where csc.ct_id = 163
and csc.code_num in (1033,1010,1011,1012,1016,1017,1016,1018)
and patins.status_cn = 1
and patins.priority = 1
-- Commented.
-- and pat.pat_id = 2561
)
select cte.[FirstName],
cte.[MiddleName],
cte.[LastName],
cte.[DOB],
cte.[AccountType],
cte.[Plan Name],
cte.DateDue
from cte
WHERE RowNumber = 1;

Related

Unexplainable SQL behaviour

I have a simple SQL query, with a handful of joined queries.
In my select I have a function shaping the date to a string format as below
LEFT(REPLACE(ADM_DT,'-',''),8)+REPLACE(ADM_TM,':','')+'00'
The script I am running should return 84 rows currently, but when executing the above in the select, it continuosly returns a different volume of rows every execution? there are no changes to the underlying tables between executions.
The strange thing is that whe I swith this back to a standard date conversion, the rows total 84
CONVERT(DATETIME,CONVERT(NVARCHAR,ADM_DT)+' '+ADM_TM)
Can anyone explain why SQL is behaving this way, I have not seen this before?
Full script below:
SELECT
[Visit ID] = a050.HSP_NO
,[Current Site] = currwd.HOSP
,[Current Specialty] = curr.SPEC
,[Current Ward] = currwd.WARD
,[Current Ward Name] = REPLACE(currwd.CURRDESC,'"','')
,[Current Consultant] = curr.PROF
,[Admission Date] = LEFT(REPLACE(ADM_DT,'-',''),8)+REPLACE(ADM_TM,':','')+'00'
,[Active] = '1'
,[PAS ID] = [crn].[crn]
,[Patient Class] = 'IP'
,NHS.[nhsno]
,CHI.CHI
,CASE WHEN OSV.X_CN IS NOT NULL THEN 'OSV' ELSE '' END OSV
,CASE WHEN NHS.[nhsno] LIKE '7%' THEN '7 NHSNO' ELSE '' END [PROBLEM NHS NO]
,DATEDIFF(D,PATS.DATE_OF_BIRTH,CONVERT(DATE,ADM_DT)) /365 [AGE ON ADMISSION]
FROM PCSSSA..SILVER.APK050_HPROVSPELL a050 WITH (NOLOCK)
-- Current Admission details
LEFT JOIN (
SELECT X_CN, CEP_NO, HSP_NO, SPEC, PROF --MSPEC
FROM PCSSSA..SILVER.APK051_CONEPIS epi WITH (NOLOCK)
-- Main Specialty Map
LEFT JOIN PCSSSA..SILVER.ENV050_DISCIPDETS en050 WITH (NOLOCK)
ON epi.SPEC = en050.OBJ_DISC
AND en050.OBJ_TYPE='SP'
AND en050.DATE_TO IS NULL
)curr
ON curr.X_CN = a050.X_CN
AND a050.HSP_NO = curr.HSP_NO
AND curr.CEP_NO = (SELECT TOP 1 a051.CEP_NO
FROM PCSSSA..SILVER.APK051_CONEPIS a051 WITH (NOLOCK)
Where a051.X_CN = a050.X_CN AND a050.HSP_NO = a051.HSP_NO
Order By CEP_NO DESC)
-- Current Ward Detail
JOIN (SELECT *, ROW_NUMBER() OVER (PARTITION BY X_CN, CEP_NO ORDER BY WS_NO DESC) AS WR
FROM PCSSSA..SILVER.APK052_WARDSTAY wdstay WITH (NOLOCK)
LEFT JOIN (SELECT
CURRWARD = OBJ_LOC,
CURRDESC = OBJ_DESC
FROM [PCSSSA]..[SILVER].[ENV030_LOCDETS] WITH (NOLOCK)
WHERE OBJ_TYPE = 'WARD'
AND DATE_TO IS NULL
)wdname
ON wdstay.WARD = wdname.CURRWARD
) currwd
ON curr.X_CN = currwd.X_CN
AND curr.CEP_NO = currwd.CEP_NO
AND currwd.WR=1
--- Admitting details
LEFT JOIN (
SELECT X_CN, CEP_NO, HSP_NO, PROF, SPEC --MSPEC
FROM PCSSSA..SILVER.APK051_CONEPIS epi WITH (NOLOCK)
-- Main Specialty Map
LEFT JOIN PCSSSA..SILVER.ENV050_DISCIPDETS en050 WITH (NOLOCK)
ON epi.SPEC = en050.OBJ_DISC
AND en050.OBJ_TYPE='SP'
AND en050.DATE_TO IS NULL
)adm
ON adm.X_CN = a050.X_CN AND a050.HSP_NO = adm.HSP_NO
AND adm.CEP_NO = (SELECT TOP 1 a051.CEP_NO
FROM PCSSSA..SILVER.APK051_CONEPIS a051 WITH (NOLOCK)
Where a051.X_CN = a050.X_CN AND a050.HSP_NO = a051.HSP_NO
Order By CEP_NO)
-- Admitting Ward Detail
JOIN (SELECT *, ROW_NUMBER() OVER (PARTITION BY X_CN,CEP_NO ORDER BY WS_NO) AS WR FROM PCSSSA..SILVER.APK052_WARDSTAY WITH (NOLOCK)) admwd
ON adm.X_CN = admwd.X_CN
AND adm.CEP_NO = admwd.CEP_NO
AND admwd.WR=1
-- Patient Detail
LEFT JOIN
(SELECT
[id].[RM_PATIENT_NO],
[id].[NUM_ID_TYPE] + CONVERT(NVARCHAR,[NUMBER_ID]) [crn]
FROM [PCSSSA]..[SILVER].[NUMBER_IDS] [id] WITH (NOLOCK)
WHERE [id].[NUM_ID_TYPE] IN ('0', '1', 'W')
)[crn]
ON a050.[X_CN] = [crn].[RM_PATIENT_NO]
-- NHS NUMBERS
LEFT JOIN
(
SELECT
[id].[RM_PATIENT_NO],
[id].[NUMBER_ID] [nhsno]
FROM [PCSSSA]..[SILVER].[NUMBER_IDS] [id] WITH (NOLOCK)
WHERE [id].[NUM_ID_TYPE] = ('NHS')
)NHS
ON NHS.RM_PATIENT_NO = a050.X_CN
-- CHI NUMBER
LEFT JOIN
(
SELECT
[id].[RM_PATIENT_NO],
[id].[NUMBER_ID] [CHI]
FROM [PCSSSA]..[SILVER].[NUMBER_IDS] [id] WITH (NOLOCK)
WHERE [id].[NUM_ID_TYPE] IN ('CHI')
)CHI
ON CHI.RM_PATIENT_NO = a050.X_CN
-- OVERSEES STATUS
LEFT JOIN
(
SELECT X_CN, [STATUS], SDATE, EDATE FROM PCSSSA..SILVER.CRS037_OSV_STATUS WITH (NOLOCK)
)OSV
ON OSV.X_CN = a050.X_CN
AND CONVERT(DATE,ADM_DT) >= OSV.SDATE
AND (OSV.SDATE IS NULL
OR CONVERT(DATE,ADM_DT) <= OSV.EDATE)
-- DEMOGRAPHICS
LEFT JOIN
(
SELECT RM_PATIENT_NO, DATE_OF_BIRTH FROM PCSSSA..[SILVER].[PATIENTS] WITH (NOLOCK)
)PATS
ON PATS.RM_PATIENT_NO = a050.X_CN
-- CURRENTLY ADMITTED ONLY
WHERE DIS_DT IS NULL
-- WITHOUT NHS NUMBER
AND (nhsno IS NULL
-- OR BRING IN ANY 7 NHS NUMBERS FOR CORRECTION
OR NHS.[nhsno] LIKE '7%'
-- ALSO INCLUDE OVERSEES
OR OSV.X_CN IS NOT NULL)
What is even stranger, is that if you wrap this in a subquery and coun(*) on the outer then it totals 84 as expected, very strange!

How I can select highest review from a user?

I need to select reviews for product, but unique by user (i.e. one review from user).
With my code, I select all reviews, and I can see few reviews left by one user.
SELECT
tr.reviewText, tr.reviewDate, tr.reviewRating,
u.userName AS userName,
u.userFirstName AS userFirstName, u.userSurname AS userSurname,
u.countryId AS countryId
FROM
tblReviews tr
INNER JOIN
tblOrderProduct op ON op.orderProductId = tr.orderProductId
AND op.productOptionId IN (SELECT productOptionId
FROM tblProductOption
WHERE productSubCuId = 111
AND productOptionActive = 1)
LEFT JOIN
tblOrder o ON o.orderId = op.orderId
LEFT JOIN
tblUser u ON u.userRandomId = o.userRandomId
WHERE
tr.reviewsStatusId = 2
ORDER BY
tr.reviewRating DESC, tr.reviewDate DESC
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
Can I get just one review from each user?
Maybe I need select userId -> group results by userId and select one per group? [I tried to do so, but I didn't succeed :( ]
You can use row_number to number the reviews and select any one like below:
;with per_user_one_review
as
(SELECT tr.reviewText, tr.reviewDate, tr.reviewRating,
u.userName as userName,
u.userFirstName as userFirstName, u.userSurname as userSurname,
u.countryId as countryId, row_number() over (partition by u.userRandomId order by tr.reviewDate desc) rn
FROM tblReviews tr
INNER JOIN tblOrderProduct op
ON op.orderProductId = tr.orderProductId
AND op.productOptionId IN (
SELECT productOptionId FROM tblProductOption
WHERE productSubCuId = 111 AND productOptionActive = 1
)
LEFT JOIN tblOrder o ON o.orderId = op.orderId
LEFT JOIN tblUser u ON u.userRandomId = o.userRandomId
WHERE tr.reviewsStatusId = 2
ORDER BY tr.reviewRating DESC, tr.reviewDate DESC
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
)
select * from per_user_one_review where rn = 1
It will pick the latest review (reviewDate desc) from the user.
If you need the last review you could use a join with the suquery for max review date grouped by orderProductId
(and as a suggestion you could use a inner join instead of a IN clasue based on a subquery)
select tr.reviewText
, tr.reviewDate
, tr.reviewRating
, u.userName
, u.userFirstName
, u.userSurname
, u.countryId
from tblReviews tr
INNER JOIN (
select max(reviewDate) max_date, orderProductId
from tblReviews
group by orderProductId
) t1 on t1.orderProductId = tr.orderProductId and t1.max_date = tr.reviewDate
INNER JOIN tblOrderProduct op ON op.orderProductId = tr.orderProductId
INNER JOIN (
SELECT productOptionId
FROM tblProductOption
WHERE productSubCuId = 111 AND productOptionActive = 1
) t2 ON op.productOptionId = t2.productOptionId
LEFT JOIN tblOrder o ON o.orderId = op.orderId
LEFT JOIN tblUser u ON u.userRandomId = o.userRandomId
WHERE tr.reviewsStatusId = 2
ORDER BY tr.reviewRating DESC, tr.reviewDate DESC
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY

Only get lastest Date time in SQL Server

I have created this code to pull tickets from our database and also pull the last ticket note date and last ticket user. It works except for if two people (or more) created a note on the last date (no matter the time difference) it will create multiple lines for each ticket. How do I fix this? here is the code:
Select distinct t.ticketID,
t.OpenDate,
c.categoryname,
s.statusname,
p.priorityname,
u.firstname,
u.lastname,
tu.firstname as 'tech_firstname',
tu.lastname as 'tech_lastname',
ltn.maxdate as 'last date',
ltu.firstname + ' ' + ltu.lastname as 'Last User'
from ticket t
left join category c on t.categoryid = c.categoryid
left join [status] s on t.statusid = s.statusid
left join [priority] p on t.priorityid = p.priorityid
left join [user] u on t.userid = u.userid
left join [user] tu on t.technicianid = tu.userid
left join ticketnote tn on t.ticketid = tn.ticketid
inner join (
Select Max(TicketNoteDate) as MaxDate, max(cast(ticketnotedate as time)) as MaxTime, ticketid, userid
From ticketNote
group by ticketid, userid) ltn on tn.ticketid = ltn.ticketid and tn.ticketnotedate = ltn.maxdate and cast(tn.ticketnotedate as time) = ltn.maxtime
left join [user] ltu on ltn.userid = ltu.userid
where t.statusid = 1
and t.LocationID = 1
order by t.ticketid
As suggested in comments, use row_number in your subquery where you get the maximum value
SELECT row_number() over
(partition by tiketid, userid
order by TicketNoteDate desc ) as rn,
ticketid,
userid,
ticketnotedate
and then join with outer query with condition being rn=1
I rewrote it getting the max date of all tickets, then finding all tickets with that max date and ordering by time descending and getting the first row and then retrieving extra data (like user) for that entry. I had no way of testing this, but here goes...
Select distinct t.ticketID,
t.OpenDate,
c.categoryname,
s.statusname,
p.priorityname,
u.firstname,
u.lastname,
tu.firstname as 'tech_firstname',
tu.lastname as 'tech_lastname',
ltn.maxdate as 'last date',
ltu.firstname + ' ' + ltu.lastname as 'Last User'
from ticket t
left join category c on t.categoryid = c.categoryid
left join [status] s on t.statusid = s.statusid
left join [priority] p on t.priorityid = p.priorityid
left join [user] u on t.userid = u.userid
left join [user] tu on t.technicianid = tu.userid
inner join (
select maxdate, maxtime, ticketid, userid, rownum from (
select maxdate, maxtime, ticketid, userid, row_number() over (order by maxdate desc, maxtime desc) as rownum
from ticketnote tn,
(Select Max(TicketNoteDate) as MaxDate
From ticketNote) mx
where mx.maxdate = tn.ticketnotedate
) x where x.rownum = 1
) ltn
left join [user] ltu on ltn.userid = ltu.userid
where t.statusid = 1
and t.LocationID = 1
order by t.ticketid

Show unique value for id, based on latest createby date

I am using the following SQL code to JOIN a few tables, but need to show unique values for the s.incidentid based on the latest s.createdate.
I know I need to use a Sub query with Maxdate, but I am not sure on the correct syntax.
This is my first query with multiple joins and I am struggling to get my head round it.
Here is my code:
SELECT
s.incidentid,
u.internalid as AssignedTo,
u.fullname as AssignedTo_FullName,
s.createby as AssignedBy,
u2.fullname as AssignedBy_FullName,
s.createdate as AssignedTime,
i.[description],
i.fix,
st.[description] as [Status],
(SELECT (CASE WHEN u.internalid = s.createby THEN 'Yes' ELSE 'No' END) as SelfAssigned),
d.d1,
d.d2,
d.d3,
d.d4,
d.d5
FROM dbo.IncidentServiceLevelAgreement s
JOIN dbo.UserAll u on u.userid = s.userid
JOIN dbo.UserAll u2 on u2.internalid = s.createby
JOIN dbo.IncidentAll i on s.incidentid = i.incidentid
JOIN dbo.[Status] st on i.statusid = st.statusid
JOIN dbo.flatdiagnosis d on i.actualdiagnosisid = d.diagnosisid
WHERE (s.groupId = '4954' and s.incidentServiceLevelAgreementTypeID = '9')
ORDER BY AssignedTime DESC
Any help greatly appreciated.
The easiest is to use a CTE and the ROW_NUMBER function:
WITH CTE AS
(
SELECT RN = ROW_NUMBER() OVER ( PARTITION BY incidentid
ORDER BY createdate DESC ),
s.Incidentid,
u.Internalid AS AssignedTo,
u.Fullname AS AssignedTo_FullName,
s.Createby AS AssignedBy,
u2.Fullname AS AssignedBy_FullName,
s.Createdate AS AssignedTime,
i.[Description],
i.Fix,
st.[Description] AS [Status],
SelfAssigned = CASE WHEN u.Internalid = s.Createby
THEN 'Yes' ELSE 'No' END,
d.D1,
d.D2,
d.D3,
d.D4,
d.D5
FROM dbo.Incidentservicelevelagreement s
JOIN dbo.Userall u
ON u.Userid = s.Userid
JOIN dbo.Userall u2
ON u2.Internalid = s.Createby
JOIN dbo.Incidentall i
ON s.Incidentid = i.Incidentid
JOIN dbo.[Status] st
ON i.Statusid = st.Statusid
JOIN dbo.Flatdiagnosis d
ON i.Actualdiagnosisid = d.Diagnosisid
WHERE ( s.Groupid = '4954'
AND s.Incidentservicelevelagreementtypeid = '9' )
)
SELECT * FROM CTE WHERE RN = 1
ORDER BY AssignedTime DESC
(instead of SELECT * list all columns explicitly, I didn't feel like it)

Returning rows selected in with statement

I have a sql statement looking something like this
WITH [ResultPage] AS (
SELECT sub.id as id, ROW_NUMBER() OVER (ORDER BY [TAG].[Name] ASC, [TAG].[ID] ASC) As [RowID], [sub].[hasPending]
FROM
(SELECT t.[ID], p.[TagID],(CASE WHEN p.[TagID] is not null THEN 1 ELSE 0 END) AS [hasPending]
FROM [Tag] AS t
full outer Join [TagPending] AS p On t.[ID] = p.[TagID]
GROUP BY t.[ID],p.[TagID]
) AS [sub]
inner Join [Tag] On [Tag].[ID] = sub.[ID]
)
SELECT [ResultPage].[RowID], [Tag].[ID] As [Tag^ID], [Tag].[Name] As [Tag^Name]
FROM [ResultPage]
INNER JOIN [Tag] ON ([Tag].[ID] = [ResultPage].[TagID])
INNER JOIN [TagPending] ON ([TagPending].[TagID] = [KbResultPage].[TagID])
WHERE (([ResultPage].[RowID] BETWEEN 1 AND 50)
)
ORDER BY [ResultPage].[RowID] ASC
As can be seen, the select max returns 50 rows at a time, however I need to know the total number of rows found in the WITH statement. I could run it again with just a count, however it could be nice if there were a way to get both in one go.
You can use the COUNT(*) OVER() in the WITH statement
WITH [ResultPage] AS (
SELECT COUNT(*) OVER() AS totalRows,
sub.id as id, ROW_NUMBER() OVER (ORDER BY [TAG].[Name] ASC, [TAG].[ID] ASC) As [RowID], [sub].[hasPending]
FROM
(SELECT t.[ID], p.[TagID],(CASE WHEN p.[TagID] is not null THEN 1 ELSE 0 END) AS [hasPending]
FROM [Tag] AS t
full outer Join [TagPending] AS p On t.[ID] = p.[TagID]
GROUP BY t.[ID],p.[TagID]
) AS [sub]
inner Join [Tag] On [Tag].[ID] = sub.[ID]
)
SELECT
[ResultPage].totalRows,
[ResultPage].[RowID], [Tag].[ID] As [Tag^ID], [Tag].[Name] As [Tag^Name]
FROM [ResultPage]
INNER JOIN [Tag] ON ([Tag].[ID] = [ResultPage].[TagID])
INNER JOIN [TagPending] ON ([TagPending].[TagID] = [KbResultPage].[TagID])
WHERE ([ResultPage].[RowID] BETWEEN 1 AND 50)
ORDER BY [ResultPage].[RowID] ASC