Find records that do not have a specific value attached - sql

I am fairly new to SQL and I'm completely stuck in this query.
I have written a query for a health organization that pulls patients info, their appointment/which provider seen the patient, what location they were seen at and what documents were created during that visit and a signoff status.
When the results return, that part of the query is accurate. (Many rows for 1 patient because of many different types of documents were generated in that one appointment)
What I am looking for, however, is to have a list of patients that have had an appointment yet "X" document was NOT created. I dont want to see the list of other documents created; specifically the appointments where "X" was not created.
Please help!
This is the query that I first explained showing the patient/appointment info, and specific documents that have been generated.
SELECT prs.person_nbr, prs.last_name + ', '+ prs.first_name as Patient, prs.date_of_birth
, pm.description AS Provider
, lm.site_id
, appts.appt_type, appts.appt_date
, pd.document_desc, pd.signoff_status
FROM person prs
, patient_documents pd
, location_mstr lm
, provider_mstr pm
, appointments appts
WHERE prs.person_id = appts.person_id
and appts.enc_id = pd.enc_id
and appts.location_id = lm.location_id
and lm.site_id is not null
and appts.rendering_provider_id = pm.provider_id
and ((pd.document_desc IN ('bms_master_im', 'Master_Im', 'BMS_ob_master','BMS_GYN_master', 'BMS_bh_master')
and pd.signoff_status = 'P')
OR (pd.document_desc IN ('bms_master_im', 'Master_Im', 'BMS_ob_master', 'BMS_GYN_master', 'BMS_bh_master')
AND pd.signoff_status IS NULL ))
ORDER BY lm.site_id, Provider
Additional info:
Tried everything suggested.
To elaborate, here's an example.
Patient: JOHN SMITH
Appointment: 20111201
Documents created: work_letter, lab_req, master_im (master_im is one of the listed to be included in the results by the IN clause)
Patient: JANE WILCOX
Appointment: 20120704
Documents created: lab_results, test_action, immunization_record.
For JOHN SMITH, the results would show that he has a master_im. Based on the already written query.
For JANE WILCOX, the results would exclude her since her documents are not listed in the IN clause. However, I want to see her in the results so that I see that she does not have a master_im or any of the other documents listed in the IN clause created.
What i'm looking for in the end is to exclude JOHN SMITH because his appointment does have the master_im document created; and to include JANE WILCOX because she has an appointment that does not have the master_im. (master_im can be substituted by any of the document values in the IN clause of my query)
***All patients who have an appointment that a) does not have "x" document created, or b) does have the "x" document created but the signoff status = P or NULL. (B is easy to figure out, only need help with part a). And we want to ignore all other documents that are not included in x.
x= 'bms_master_im', 'master_im',' bms_ob_master', 'bms_gyn_master', 'bms_bh_master', 'ob_master', 'gyn_master', 'bh_master')

You need to expand your WHERE clause by adding a condition on the field that contain the "X" values you speak of. Assuming this field is located in patient_documents.code, your WHERE clause becomes:
WHERE prs.person_id = appts.person_id
and appts.enc_id = pd.enc_id
and appts.location_id = lm.location_id
and lm.site_id is not null
and appts.rendering_provider_id = pm.provider_id
and pd.code not in ('X', '...')
and ((pd.document_desc IN ('bms_master_im', 'Master_Im', 'BMS_ob_master','BMS_GYN_master', 'BMS_bh_master')
and pd.signoff_status = 'P')
OR (pd.document_desc IN ('bms_master_im', 'Master_Im', 'BMS_ob_master', 'BMS_GYN_master', 'BMS_bh_master')
AND pd.signoff_status IS NULL ))
Note that I added the line with the whitespace on top and below. Of course, if the field containing the code is named differently, you should modify the field reference.

Edited:
You need to use JOIN clauses on your tables, and a left join on the documents table.
For Example:
FROM person prs,
JOIN appointments appts ON prs.person_id = appts.person_id
JOIN location_mstr lm ON appts.location_id = lm.location_id
JOIN provider_mstr pm ON ...
Then
LEFT JOIN patient_documents pd ON ...

Related

Having SQL Server choose and show one record over other

Ok, hopefully I can explain this accurately. I work in SQL Server, and I am trying to get one row from a table that will show multiple rows for the same person for various reasons.
There is a column called college_attend which will show either New or Cont for each student.
My issue: my initial query narrows down the rows I'm pulling by Academic Year, which consists of two semesters: Fall of one year, and Spring of the following to create an academic year. This is why there are two rows returned for some students.
Basically, I need to generate an accurate count of those that are "New" and those that are "Cont", but I don't want both records for the same student counted. They will have two records because they will have one for spring and one for fall (usually). So if a student is "New" in fall, they will have a "Cont" record for spring. I want the query to show ONLY the "New" record if they have both a "New' and "Cont" record, and count it (which I will do in Report Builder). The other students will basically have two records that are "Cont": one for fall, and one "Cont" for spring, and so those would be considered the continuing ones or "Cont".
Here is the basic query I have so far:
SELECT DISTINCT
people.people_id,
people.last_name,
people.first_name,
academic.college_attend AS NewORCont,
academic.academic_year,
academic.academic_term,
FROM
academic
INNER JOIN
people ON people.people_id = academic.people_id
INNER JOIN
academiccalendar acc ON acc.academic_year = academic.academic_year
AND acc.academic_term = academic.academic_term
AND acc.true_academic_year = #Academic_year
I'm not sure if this can be done with a CASE statement? I thought of a GROUP BY, but then SQL Server will want me to add all of my columns to the GROUP BY clause, and that ends up negating the purpose of the grouping in the first place.
Just a sample of what I work with for each student:
People ID
Last
First
NeworCont
12345
Soanso
Guy
New
12345
Soanso
Guy
Cont
32345
Person
Nancy
Cont
32345
Person
Nancy
Cont
55555
Smith
John
New
55555
Smith
John
Cont
---------
------
-------
----------
Hopefully this sheds some light on the duplicate record issue I mentioned.
Without sample data its awkward to visualize the problem, and without the expected results specified it's also unclear what you want as the outcome. Perhaps this will assist, it will limit the results to only those who have both 'New' and 'Cont' in a single "true academic year" but the count seems redundant as this (I imagine) will always be 2 (being 1 New term and 1 Cont term)
SELECT
people.people_id
, people.last_name
, people.first_name
, acc.true_academic_year
, count(*) AS count_of
FROM academic
INNER JOIN people ON people.people_id = academic.people_id
INNER JOIN academiccalendar acc ON acc.academic_year = academic.academic_year
AND acc.academic_term = academic.academic_term
AND acc.true_academic_year = #Academic_year
GROUP BY
people.people_id
, people.last_name
, people.first_name
, acc.true_academic_year
HAVING MAX(academic.college_attend) = 'New'
AND MIN(academic.college_attend) = 'Cont'

SQL Looking up prior record information

Here is my situation. I have a series of claims for a person. We occasionally get a duplicate claim which is given a DUP error code and and denied with zero dollar amount. What I am trying to do is look up the original claim units and billed amount. If the duplicate and the original claim are the same units and billed amount I intend to ignore it (or at least label it as NOT a potential re-bill). If the units and/or the billed amount are different, that claim will be labeled as a potential re-bill.
I've got a function that correctly finds the original claim primary key value and the base query runs in less than a second. However, when I try to link that dataset back to the tables it crushes my run time to the point of uselessness. What I don't understand is why does the function alone run so quickly but attempting to link it back bogs it down so much, we are talking about a dataset of 140ish claims over a year of activity.
If anyone could offer some insight or has a better way to accomplish this I would be obliged.
SELECT pre.*
--, st.unitsofservice as OrigUnits
--I only include the line above if the link to the servicetransaction table on the last line of the query is active
FROM
(
SELECT Sub.*--,
,dbo.cf_DuplicateServiceSTID(sub.servicetransactionid) as PaidSvc
--the line above is the function returning the primary key value for the original claim
FROM
(
SELECT Pre.servicetransactionID,
st.servicedate, st.individualid, st.agencyid, st.servicecode, st.placeofserviceid, st.unitsofservice,
dbo.sortmodifiers(st.modifiercodeid, st.modifiercodeid2, st.modifiercodeid3, st.modifiercodeid4) as Modifiers,
bd.billedamount,
a.upi,
b.name
FROM (select pmt.servicetransactionid
from pmtadjdetail pmt
where substring(pmt.reasoncodes,1,5) = 'DUP') Pre
JOIN servicetransaction st on pre.servicetransactionid = st.servicetransactionid
join billdetail bd on st.servicetransactionid = bd.servicetransactionid
join agency a on st.agencyid = a.agencyid
join business b on a.businessid = b.businessid
where st.servicedate between #StartDate and #EndDate
and st.agencyid = iif(#AgencyID is null, st.agencyid, #AgencyID)
) Sub
join individual i on sub.individualid = i.individualid
join enrollment e on sub.individualid = e.individualid
WHERE e.enrollmenttype <> 'p'
) Pre
--join servicetransaction st on pre.paidsvc = st.servicetransactionid
--If I remove the comment from the line above my run time increases to the point of uselessness

How to return 1st record from group by

Trying to return only the 1st supplier code and have all other fields unaffected.
`Select
Container.Part_Key,
Part.Part_No,
Part.Name,
Part.Revision,
Container.Quantity,
Container.Container_Status,
OP.Operation_No,
Opp.Operation_Code,
Part.Part_Status,
Supplier.Supplier_Code
From Part_v_Container as Container
Join Part_v_Part as Part
ON Part.Part_Key = Container.Part_Key
Join Part_v_Part_Operation as Op
On Op.Part_Operation_Key = Container.Part_Operation_Key
Join Part_v_Operation as OPP
On OPP.Operation_Key = OP.Operation_Key
Join part_v_approved_supplier as Approved
On Approved.part_key = container.part_key
Join common_v_Supplier as Supplier
On Supplier.supplier_no = Approved.Supplier_No
Where Container.Active = '1'
group by container.part_key`
There will be duplicate part numbers, revisions, etc. Not worried about that. I just want the part no to list only one approved supplier to the far right, even though for any given part, there are multiple approved suppliers listed in the database.
Furthermore, the order the database lists the approved suppliers does not matter.
Thanks!
Add a sub query in your select list
( select top 1 supplier.supplier_code
From supplier
Where Supplier.supplier_no = Approved.Supplier_No order by Supplier.supplier_no) as supplier code
This can be the last field in the select list
You could add An appropriate order by.
This would work in SQL Server

How to find bad references in a table in Oracle

I have a data problem I need to clean up. Basically I have two tables storing "package" information, one table for documents and one table for audit information. I have entries in the package tables that reference documents that no longer exist and have been replaced (same name but different id) and I want to write a query to find all the bad ones and which new document should replace them. The only thing linking these two is a string value in the audit table which stores the document name (not id).
I've setup a sample schema here: http://sqlfiddle.com/#!4/997bda/1
package_s is the single values for a package in our application
package_r is the repeating values for a package in our application
(these are joined with the same value in the id column)
audit_info is all the audit information in a package
docs is all the documents that can be attached to a package
This query finds the packages with bad attachments (may be more than one per package)
select distinct ps.pkgname, pr.doc_list
from package_s ps, package_r pr
where ps.id = pr.id
and not exists (
select 1 from docs
where pr.doc_list = id
)
order by 1,2 asc
;
I need to build a query with the following rules:
I need to return at least the package id, the position value and the new document id (I will build an update statement to put this new document id in the row matching the package id / position in the package_r table)
the way to get the document name from the audit information is:
SUBSTR(description,0,INSTR(description,'[')-2)
If the document was Added and then Removed, it should be ignored (string_1)
string_2 must not be 'Supporting'
the new document must match
state = 'Master'
latest = 1
pub = '0'
Right now I have a semi-working script that works on a per package basis, but the problem is affecting 2000+ packages. I find the audit entries that don't match documents correctly attached to the package and then search for those names in the document table. The problem with this is since there is no direct link between the package and document tables, if there are multiple problem attachments on one package, each "new" document is returned once per position value, i.e.
package id bad doc id position new doc id
p1 d1 -1 d1-new
p1 d1 -1 d4-new
p1 d4 -2 d1-new
p1 d4 -2 d4-new
It doesn't matter which new id goes into which position value, but the duplication result problem like this makes it hard to mass generate update scripts, some manual filtering would be required.
This is a somewhat complex and unique data issue, so any help would be greatly appreciated.
This query works according to informations provided:
with ai as (
select a1.audited_id id, dc.id doc_id, dc.docname,
row_number() over (partition by a1.audited_id order by dc.id) rn
from audit_info a1
join docs dc
on dc.state = 'Master' and dc.latest = 1 and dc.pub = '0'
and dc.docname = substr(a1.description, 1, instr(a1.description, '[')-2)
where string_1 = 'Added' and string_2 <> 'Supporting'
and not exists (
select * from audit_info a2
where a2.audited_id = a1.audited_id and string_1 = 'Removed'
and a2.description = a1.description )
and not exists ( -- here matching docs are eliminated
select 1 from package_r pr
where pr.id = a1.audited_id and pr.doc_list = dc.id ) ),
p as (
select ps.id, ps.pkgname, pr.doc_list, pr.position,
row_number() over (partition by ps.id order by doc_list) rn
from package_s ps
join package_r pr on pr.id = ps.id
where not exists ( select * from docs where pr.doc_list = docs.id )
)
select p.id, p.pkgname, p.doc_list, p.position
, ai.docname, ai.doc_id
from p join ai on ai.id = p.id and p.rn = ai.rn
order by p.id, p.doc_list, ai.doc_id
Output:
ID PKGNAME DOC_LIST POSITION DOCNAME DOC_ID
-- ------- -------- -------- ------- ------
p1 000001 d3 -3 doc3 d3-new
p1 000001 d4 -4 doc4 d4-new
p2 000002 d5 -2 doc5 d5-new
p4 000004 d6 -1 doc6 d6-new
Edit: Answers to issues reported in comments
it is identifying packages that do not have bad values, and then the doc_list column is blank,
Note that query (my subquery p) for identyfing packages is basically your query, I just added counter there.
I guess that some process/application or someone manually cleared column doc_list in package_r.
If you don't want such entries, just add condition and trim(doc_list) is not null in subquery p.
for the ones it gets right on the package part (they have a bad value) it is bringing back the wrong docname/doc_id to replace the bad value with, it is a different doc_id in the list.
I understand this only partially. Can you add such entries to your examples (in Fiddle or just edit your question and add problematic input rows and expected output for them?)
"It doesn't matter which new id goes into which position value".
Assignment I made this way - if we had two old docs with names "ABC", "DEF" and corrected docs have names "XXA", "DE12"
then they will be linked as "ABC"->"DE12" and "DEF"->"XXA" (alphabetical ordering seems more rational than totally random).
To make assigning random change order by ... to order by null in both row_number() functions.

Match All Records

I am having difficulty with writing an SQL query for my application. Below shows a screenshot of some of the tables in my database.
Please let me explain how a section of my application works, and then I can show you the problem I am having with my SQL query.
A User can create an application form on my system (dbo.Form). An application form consists of several sections, one of those sections is Employment History (dbo.FormEmployment). An employment record includes details like employer name, start date etc, but also a gradeID. A User can add one or more employment records to the table dbo.FormEmployment.
A system administrator can add a Shift (dbo.Shift) to the system, and also then assign Grades to a Shift. These Grades are recorded in the dbo.ShiftGrade table. A Shift can be assigned 1 or more Grades, i.e. it could be assigned 1,2,3,4 or 5 Grades.
When the system administrator has added the Shift and Shift Grades, I then want to perform an SQL query to return a list of Users whose Grades match that of the Grades assigned to a Shift (remember the User adds their Grade when they add an employment record).
I have written the following SQL query which works, however, the issue with this query is that it returns a list of Users, that have any Grade that matches that of the Grades assigned to a Shift.
SELECT u.userID, u.userTypeID, u.firstName, u.lastName, u.email, u.password,
u.contactNumber, u.organisationID, u.emailVerificationCode, u.mobileVerificationCode,
u.userStatusID, u.AddedBy, u.AddedDate, u.ModifiedBy, u.ModifiedDate
FROM [User] u
--Check Grades Match
WHERE u.userID IN
(
SELECT f.locumID
FROM dbo.Form f, dbo.FormEmployment emp
WHERE f.formID = emp.formID
AND emp.statusID = 101
AND emp.workYN = 1
AND emp.gradeID IN (
select gradeID from dbo.ShiftGrade where shiftID = #p0
)
)
You can see I am using the IN statement to do this. However, I only want to return a list of Users who can match exactly the same Grades that have been assigned to a Shift. Therefore, if a Shift has been assigned 3 Grades, then I want a List of Users who also have the exact same three Grades to be returned.
I apologise for the lengthy post, I just thought it would be better explained this way.
Any feedback or help with this would be greatly appreciated.
select u.*
from dbo.Users u
join dbo.Form f on u.? = f.formId
join dbo.FormEmployment fe on fe.formId = f.formId
join dbo.Grade g on g.gradeId = fe.gradeId
join dbo.ShiftGrade shg on shg.gradeId =g.gradeId
join dbo.Shift sh on sh.shiftId = shg.shiftId
where
sh.shiftId = -- recently added shift id
and g.gradeId == -- recently added grade id