Nested query WHERE procedure code IN and AND - sql

Would like to take the following Query and alter it so that it brings back ONLY records where each patient (based on MRN) has BOTH ProcedureCodeList IN ('115-1','117-1','311-1') AND ProcedureCodeList = '119-103'
SELECT P.SiteID, O.ProcedureCodeList, P.MRN, PINFO.LastName, PINFO.FirstName, PINFO.[State] AS Species, PINFO.City AS Breed, O.ProcedureDescList, RF.FieldName, RF.FieldValue, R.ContentText
, R.LastSignDate
FROM ReportFinding RF
INNER JOIN Report R
ON RF.ReportID = R.ReportID
INNER JOIN [Order] O
ON R.ReportID = O.ReportID
INNER JOIN Visit V
ON O.VisitID = V.VisitID
INNER JOIN Patient P
ON P.PatientID = V.PatientID
INNER JOIN PersonalInfo PINFO
ON P.PersonalInfoID = PINFO.PersonalInfoID
WHERE
O.ProcedureCodeList IN ('115-1','117-1','119-103')
ORDER BY R.LastSignDate DESC

There are a couple of ways to solve this. One way is to create two subqueries and join them on the MRN.
SELECT a.SiteID, a.ProcedureCodeList, a.MRN, a.LastName, a.FirstName, a.Species, a.Breed, a.ProcedureDescList, a.FieldName, a.FieldValue, a.ContentText, a.LastSignDate
FROM
(SELECT P.SiteID, O.ProcedureCodeList, P.MRN, PINFO.LastName, PINFO.FirstName, PINFO.[State] AS Species, PINFO.City AS Breed, O.ProcedureDescList, RF.FieldName, RF.FieldValue, R.ContentText, R.LastSignDate
FROM ReportFinding RF
INNER JOIN Report R ON RF.ReportID = R.ReportID
INNER JOIN [Order] O ON R.ReportID = O.ReportID
INNER JOIN Visit V ON O.VisitID = V.VisitID
INNER JOIN Patient P ON P.PatientID = V.PatientID
INNER JOIN PersonalInfo PINFO ON P.PersonalInfoID = PINFO.PersonalInfoID
WHERE O.ProcedureCodeList IN ('115-1','117-1','119-103')) as a
JOIN
(SELECT P.MRN
FROM [Order]
INNER JOIN Visit V ON O.VisitID = V.VisitID
INNER JOIN Patient P ON P.PatientID = V.PatientID
WHERE O.ProcedureCodeList = '119-103') as b ON a.MRN = b.MRN
ORDER BY a.LastSignDate
The PersonalInfo table is not needed in the second query. I don't think ReportFinding and Report are either, based on your JOINs. It depends on what these tables are actually doing.
Another way starts with the original query and adds the following to the WHERE clause (before the ORDER BY):
AND P.MRN IN
(SELECT P.MRN
FROM [Order]
INNER JOIN Visit V ON O.VisitID = V.VisitID
INNER JOIN Patient P ON P.PatientID = V.PatientID
WHERE O.ProcedureCodeList = '119-103')
I would look at the execution plans of both solutions to know which is the better one in this case.

Related

MAX or MIN on SQL table value with condition

Hi I was hoping someone could tell me a better way to do this, what I have works, but it is slow and is causing my query to run over 4 seconds. The tables all have indexes on and I can't see anything in the execution plans in particular.
I want to get the min assessmentId where initial = 1, and also the max assessmentId altogether from my table.
Is there a better way that joining the table twice?
select
r.PatientId,
MAX(r.ReferralId),
MIN(a.AssessmentOneId),
MAX(a1.AssessmentOneId)
from dbo.Referral r
inner join dbo.Patient p on p.PatientId = r.PatientId
left join dbo.AssessmentOne a on a.ReferralId = r.ReferralId and a.Initial = 1
left join dbo.AssessmentOne a1 on a1.ReferralId = r.ReferralId
where
p.AccountId = #pAccountId
group by r.PatientId
I've also tried the following using sub queries, but I am still getting bad performance.
select
r.PatientId,
MAX(r.ReferralId),
(Select MIN(a.AssessmentOneId) from dbo.AssessmentOne a where a.ReferralId = MAX(r.ReferralId) and a.Initial = 1),
(Select MAX(a.AssessmentOneId) from dbo.AssessmentOne a where a.ReferralId = MAX(r.ReferralId))
from dbo.Referral r
inner join dbo.Patient p on p.PatientId = r.PatientId
where
p.AccountId = #pAccountId
group by r.PatientId
Any help you can give would be appreciated
For this query:
select r.PatientId, MAX(r.ReferralId), MIN(a.AssessmentOneId),
MAX(a1.AssessmentOneId)
from dbo.Referral r inner join
dbo.Patient p
on p.PatientId = r.PatientId left join
dbo.AssessmentOne a
on a.ReferralId = r.ReferralId left join
dbo.AssessmentOne a1
on a1.ReferralId = r.ReferralId
where p.AccountId = #pAccountId
group by r.PatientId;
I would recommend indexes on Patient(AccountId, PatientId), Referral(PatientId, ReferralId), and AssessmentOne(ReferalId, Initial).
The double join is a bit strange. So, I would write this as:
select p.PatientId, max(r.ReferralId), max(a.AssessmentOneId),
max(case when a.Initial = 1 then a.AssessmentOneId end)
from dbo.Referral r inner join
dbo.Patient p
on p.PatientId = r.PatientId left join
dbo.AssessmentOne a
on a.ReferralId = r.ReferralId
where p.AccountId = #pAccountId
group by p.PatientId;
I doubt this really affects performance, but it seems simpler to me.
The referral table is a bridge table for the m:n relation of patient and assessment. As you want certain assessment IDs per patient, it's necessary to join the tables, what you are already doing. However, as we must look up all assessments per patient to get the maximum number, we can get the minimum initial assessment ID on-the-fly:
select
p.patientid,
max(r.referralid),
min(case when initial = 1 then assessmentoneid end),
max(assessmentoneid)
from dbo.patient p
join dbo.referral r on on r.patientid = p.patientid
left join dbo.assessmentone a on a.referralid = r.referralid
where p.accountid = #paccountid
group by p.patientid;
You'll want these indexes:
patient (accountid, patientid)
referral (patientid, referralid)
assessmentone (referralid, assessmentoneid, initial)

How to select top when already selected fields

Just wanted to ask how to add a 'select top 1 *' when I've already selected fields from a list? I seen examples in other codes but don't quite get it. Thought will be easier if see it in a code I constructed.
Below is an example of a query I have:
select frp.ProductPersonID,frp.FlightSeatId, frp.PlusMealId, per.TitleID, per.surname, per.FirstName, per.PersonTypeId, tor.PersonID, tor.Reference
from package pk
inner join product p on p.packageid = pk.packageid
inner join productperson pp on pp.productid = p.productid
inner join person per on per.personid = pp.personid
left join flightlogicalseat fls on fls.productpersonid = pp.productpersonid
inner join TourOperatorReference tor on tor.PersonID = per.PersonId
inner join FlightReservationPassenger frp on frp.ProductPersonID = pp.ProductPersonId
where pk.Reference LIKE '%'
and ProductTypeId =1
Simply try to use TOP keyword like this:
select TOP 1 frp.ProductPersonID,frp.FlightSeatId, frp.PlusMealId, per.TitleID,
You can just wrap your existing query in new query:
SELECT TOP 1 * FROM
(select frp.ProductPersonID,frp.FlightSeatId, frp.PlusMealId, per.TitleID, per.surname, per.FirstName, per.PersonTypeId, tor.PersonID, tor.Reference
from package pk
inner join product p on p.packageid = pk.packageid
inner join productperson pp on pp.productid = p.productid
inner join person per on per.personid = pp.personid
left join flightlogicalseat fls on fls.productpersonid = pp.productpersonid
inner join TourOperatorReference tor on tor.PersonID = per.PersonId
inner join FlightReservationPassenger frp on frp.ProductPersonID = pp.ProductPersonId
where pk.Reference LIKE '%'
and ProductTypeId =1) t

How to retrieve count of records in SELECT statement

I am trying to retrieve the right count of records to mitigate an issue I am having. The below query returns 327 records from my database:
SELECT DISTINCT COUNT(at.someid) AS CountOfStudentsInTable FROM tblJobSkillAssessment AS at
INNER JOIN tblJobSkills j ON j.jobskillid = at.skillid
LEFT JOIN tblStudentPersonal sp ON sp.someid2 = at.someid
INNER JOIN tblStudentSchool ss ON ss.monsterid = at.someid
INNER JOIN tblSchools s ON s.schoolid = ss.schoolid
INNER JOIN tblSchoolDistricts sd ON sd.schoolid = s.schoolid
INNER JOIN tblDistricts d ON d.districtid = sd.districtid
INNER JOIN tblCountySchools cs ON cs.schoolid = s.schoolid
INNER JOIN tblCounties cty ON cty.countyid = cs.countyid
INNER JOIN tblRegionUserRegionGroups rurg ON rurg.districtid = d.districtid
INNER JOIN tblGroups g ON g.groupid = rurg.groupid
WHERE ss.graduationyear IN (SELECT Items FROM FN_Split(#gradyears, ',')) AND sp.optin = 'Yes' AND g.groupname = #groupname
Where I run into trouble is trying to reconcile that with the below query. One is for showing just a count of all the particular students the other is showing pertinent information for a set of students as needed but the total needs to be the same and it is not. The below query return 333 students - the reason is because the school the student goes to is in two separate counties and it counts that student twice. I can't figure out how to fix this.
SELECT DISTINCT #TableName AS TableName, d.district AS LocationName, cty.county AS County, COUNT(DISTINCT cc.monsterid) AS CountOfStudents, d.IRN AS IRN FROM tblJobSkillAssessment AS cc
INNER JOIN tblJobSkills AS c ON c.jobskillid = cc.skillid
INNER JOIN tblStudentPersonal sp ON sp.monsterid = cc.monsterid
INNER JOIN tblStudentSchool ss ON ss.monsterid = cc.monsterid
INNER JOIN tblSchools s ON s.schoolid = ss.schoolid
INNER JOIN tblSchoolDistricts sd ON sd.schoolid = s.schoolid
INNER JOIN tblDistricts d ON d.districtid = sd.districtid
INNER JOIN tblCountySchools cs ON cs.schoolid = s.schoolid
INNER JOIN tblCounties cty ON cty.countyid = cs.countyid
INNER JOIN tblRegionUserRegionGroups rurg ON rurg.districtid = d.districtid
INNER JOIN tblGroups g ON g.groupid = rurg.groupid
WHERE ss.graduationyear IN (SELECT Items FROM FN_Split(#gradyears, ',')) AND sp.optin = 'Yes' AND g.groupname = #groupname
GROUP BY cty.county, d.IRN, d.district
ORDER BY LocationName ASC
If you just want the count, then perhaps count(distinct) will solve the problem:
select count(distinct at.someid)
I don't see what at.someid refers to, so perhaps:
select count(distinct cc.monsterid)

Sql join 1 instance

I require some help with my very shaky sql skills.
Say I have the following select statement:
SELECT DISTINCT
p.ProjectId,
p.Title,
i.Name,
p.StartDate,
p.EndDate,
ped.ProjectEthicsDocumentId,
st.Description AS StatusText
FROM
dbo.Project p
inner join dbo.WorkflowHistory w ON p.ProjectId = w.ProjectId
left join dbo.ProjectInstitution pi ON pi.ProjectId = p.ProjectId
left join dbo.Institution i ON i.InstitutionId = pi.InstitutionId
left join dbo.ProjectEthicsDocument ped on p.ProjectId = ped.ProjectId
left join dbo.Status st ON p.StatusId = st.StatusId
This will return all the projects and other relevant details from the relevant tables. Now, say I have 2 institutions for 'Project A'. This statement will return 2 rows for 'Project A', one for each institution. How do I set it so that it only returns the first row of each project it finds? I want one instance of every project with say the first institution found.
The easiest way is probably with the row_number() function:
select *
from (SELECT DISTINCT p.ProjectId, p.Title, i.Name, p.StartDate,p.EndDate,
ped.ProjectEthicsDocumentId, st.Description AS StatusText,
row_number() over (partition by p.ProjectId order by i.InstitutionId) as seqnum
FROM dbo.Project p
inner join dbo.WorkflowHistory w ON p.ProjectId = w.ProjectId
left join dbo.ProjectInstitution pi ON pi.ProjectId = p.ProjectId
left join dbo.Institution i ON i.InstitutionId = pi.InstitutionId
left join dbo.ProjectEthicsDocument ped on p.ProjectId = ped.ProjectId
left join dbo.Status st ON p.StatusId = st.StatusId
) p
where seqnum = 1;
You can move selecting institution name to a subquery. This way you it doesn't affect how other tables are joined.
SELECT DISTINCT
p.ProjectId,
p.Title,
(SELECT TOP 1 i.Name FROM dbo.Institution i
INNER JOIN dbo.ProjectInstitution pi ON i.InstitutionId = pi.InstitutionId
WHERE pi.ProjectId = p.ProjectId) AS Name,
p.StartDate,
p.EndDate,
ped.ProjectEthicsDocumentId,
st.Description AS StatusText
FROM
dbo.Project p
inner join dbo.WorkflowHistory w ON p.ProjectId = w.ProjectId
left join dbo.ProjectEthicsDocument ped on p.ProjectId = ped.ProjectId
left join dbo.Status st ON p.StatusId = st.StatusId
you could use
;with cte as
(
<your select statement> `,`
Row_number() over(partition by <column that has 2 records> order by ProjectId) as rn
)
--then do this
select * from cte where rn=1

SQL use nested select in middle of inner join

Is it possible to use a select in the middle of joining...
I am trying to do the following:
FROM
tblorders o
INNER JOIN tblunits u on o.id = u.orderid
INNER JOIN ((SELECT
,Min(n.date) as [MinDate]
from tblNotes n
Where n.test = 'test') te
INNER JOIN tblnotes n on te.id = n.id
and te.[MinDate] = n.AuditinsertTimestamp)
INNER Join tblClient c ON o.ClientId = c.Id
Basically in the select in the middle of the query it is selecting only the notes with min date. The problem is I need to do this here because I need from tblOrders to be the first table.......
Suggestions?
The INNER JOIN failed because you have a leading comma here:
,Min(n.date) as [MinDate]
I think you are looking for something like this:
SELECT ...
FROM tblorders o
INNER JOIN tblunits u on o.id = u.orderid
INNER JOIN (
SELECT id, Min(date) as [MinDate]
from tblNotes
Where test = 'test'
group by id
) te <-- not sure what JOIN clause to use here, please post schema
INNER JOIN tblnotes n on te.id = n.id
and te.[MinDate] = n.AuditinsertTimestamp
INNER Join tblClient c ON o.ClientId = c.Id
You are missing an alias and join condition:
FROM
tblorders o
INNER JOIN tblunits u on o.id = u.orderid
INNER JOIN ((SELECT Min(n.date) as [MinDate]
from tblNotes n
Where n.test = 'test') te
INNER JOIN tblnotes n on te.id = n.id
and te.[MinDate] = n.AuditinsertTimestamp)
-- missing
AS z
ON <join conditions haere>
INNER Join tblClient c ON o.ClientId = c.Id
Yes, you can have a Select in a Join.