NOT IN not working sufficient - sql

I wrote this to get me the patients who have never had the diagnosis codes stated. But I am getting results of people who DID. Only that it's NOT displaying that codes in the output but other codes they have.
But I need to not include the patient who has that code but the NOT IN part
is not working or what else am I missing?
select Distinct a.voucher_primary_diagnosis_code, a.Patient_Number, b.Patient_Name vwGenVouchInfo a
left join vwGenPatInfo b on a.Patient_Number=b.patient_number
where
a.Department_Descr = 'Pediatrics' and Actual_Dr_ID <> 6 and Voucher_Primary_Diagnosis_Code not in
('Z00.129', 'Z00.00') order by patient_name

NOT IN condition applies to a single row. However, you are looking for non-existence of any rows associated with the given patient that match the specified codes, so you need a different condition: you need to say that for a given patient there's no diagnosis code on the specified list. For example, you could use EXISTS quantifier for that:
SELECT
a.voucher_primary_diagnosis_code
, a.Patient_Number
, b.Patient_Name
FROM vwGenVouchInfo a
LEFT JOIN vwGenPatInfo b ON a.Patient_Number=b.Patient_Number
WHERE
a.Department_Descr = 'Pediatrics'
AND Actual_Dr_ID <> 6
AND NOT EXISTS (
-- This subquery looks at other vouchers of the same patient.
-- If any of them has Diagnosis Code from the prohibited list,
-- all records for that patient are rejected.
SELECT *
FROM vwGenVouchInfo v
WHERE v.Patient_Number=b.Patient_Number
AND v.Voucher_Primary_Diagnosis_Code IN ('Z00.129', 'Z00.00')
)
ORDER BY Patient_Name

You can do this with a left join. Here is one way to get the patients who meet your description:
select p.Patient_Number, p.Patient_Name
from vwGenPatInfo p left join
vwGenVouchInfo v
on p.Patient_Number = v.patient_number and
v.Department_Descr = 'Pediatrics' and
v.Actual_Dr_ID <> 6 and
v.Voucher_Primary_Diagnosis_Code in ('Z00.129', 'Z00.00')
where v.patient_number is null
order by p.patient_n
Note this doesn't return information about diagnoses, because you are getting the patients who don't have the diagnoses you care about.

Related

SQL Left Join - OR clause

I am trying to join two tables. I want to join where all the three identifiers (Contract id, company code and book id) are a match in both tables, if not match using contract id and company code and the last step is to just look at contract id
Can the task be performed wherein you join using all three parameters, if does not, check the two parameters and then just the contract id ?
Code:
SELECT *
INTO #prem_claim_wtauto_test
FROM #contract_detail A
LEFT JOIN #claim_total C
ON ( ( C.contract_id_2 = A.contract_id
AND C.company_cd_2 = A.company_cd
AND C.book_id_2 = A.book_id )
OR ( C.contract_id_2 = A.contract_id
AND C.company_cd_2 = A.company_cd )
OR ( C.contract_id_2 = A.contract_id ) )
Your ON clause boils down to C.contract_id_2 = A.contract_id. This gets you all matches, no matter whether the most precise match including company and book or a lesser one. What you want is a ranking. Two methods come to mind:
Join on C.contract_id_2 = A.contract_id, then rank the rows with ROW_NUMBER and keep the best ranked ones.
Use a lateral join in order to only join the best match with TOP.
Here is the second option. You forgot to tell us which DBMS you are using. SELECT INTO looks like SQL Server. I hope I got the syntax right:
SELECT *
INTO #prem_claim_wtauto_test
FROM #contract_detail A
OUTER APPLY
(
SELECT TOP(1) *
FROM #claim_total C
WHERE C.contract_id_2 = A.contract_id
ORDER BY
CASE
WHEN C.company_cd_2 = A.company_cd AND C.book_id_2 = A.book_id THEN 1
WHEN C.company_cd_2 = A.company_cd THEN 2
ELSE 3
END
);
If you want to join all rows in case of ties (e.g. many rows matching contract, company and book), then make this TOP(1) WITH TIES.

Oracle sql query that returns customers who are coming for the first time in property

I have 3 tables: customer, property and stays. Table customer contains all the data about customers (customer_id, name, surname, email...). Table property contains the list of all the properties (property_id, property_name...) and table stays contains all the earlier stays of customers (customer_id, property_id, stay_id, arrival_date, departure_date...).
Some customers stayed multiple times in more than one properties and some customers are coming for the first time.
Can someone please explain oracle sql query which returns only the customers who are stying in any of the properties for the first time.
Sorry guys for answering late..
This is what I got so far.
Tables:
Customer $A$
Stays $B$
Property $C$
Customer_Fragments $D$
SELECT a.RIID_,
sub.CUSTOMER_ID_,
sub.PROPERTY_ID,
b.ARRIVAL_DATE,
c.PROPERTY_SEGMENT,
ROW_NUMBER() OVER (
PARTITION BY sub.CUSTOMER_ID_,
sub.PROPERTY_ID
ORDER BY
sub.CUSTOMER_ID_ asc
) RN
FROM
(
SELECT
b.CUSTOMER_ID_,
b.PROPERTY_ID
FROM
$B$ b
GROUP BY
b.CUSTOMER_ID_,
b.PROPERTY_ID
HAVING
COUNT(*)= 1
) sub
INNER JOIN $A$ a ON sub.CUSTOMER_ID_ = a.CUSTOMER_ID_
INNER JOIN $B$ b ON sub.CUSTOMER_ID_ = b.CUSTOMER_ID_
INNER JOIN $C$ c ON sub.PROPERTY_ID = c.PROPERTY_ID
LEFT JOIN $D$ d ON a.RIID_ = d.RIID_
WHERE
b.ARRIVAL_DATE = TRUNC(SYSDATE + 7)
AND c.PROPERTY_DESTINATION = 'Destination1'
AND lower(c.NAME_) NOT LIKE ('unknown%')
AND a.NWL_PERMISSION_STATUS = 'I'
AND a.EMAIL_DOMAIN_ NOT IN ('abuse.com', 'guest.booking.com')
AND (d.BLACKLISTED != 'Y'
or d.BLACKLISTED is null
)
I want to select all customers who will come to Destination1, 7days from today to inform them about some activities. Customers can book several
properties in Destination1 and have the same arrival date (example: I can book a room in property1 for me and my wife and also book a room in property2 for my friends.. and we all come to destination1 on the same arrival date).
When this is the case I want to send just one info email to a customer and not two emails. The above SQL query returns two rows when this is the case and I want it to return just one row (one row = one email).
It is always required to post a code you have already tried to write so that we can than help you with eventual mistakes.
After that being said, I'll try to help you nevertheless, writing the full code.
Try this:
select cus.*
from customers cus
join stays st
on st.customer_id = cus.customer_id
where st.arrival_date >= YOUR_DATE --for example SYSDATE or TRUNC(SYSDATE)
and 1 = (select count(*)
from stays st2
where st2.customer_id = cus.customer_id)
You haven't specified it, but I GUESS that you are interested in getting the first-time-customers whose arrival date will be at or after some specified date. I've written that into my code in WHERE clause, where you should input such a date.
If you remove that part of the WHERE clause, you'll get all the customers that stayed just once (even if that one and only stay was 10 years ago, for example). What's more, if you remove that part of the code, you can than also remove the join on stays st table from the query too, as the only reason for that join was the need to have access to arrival date.
If you need explanations for some other parts of the code too, ask in the comments for this answer.
I hope I helped!
WITH first_stays (customer_id, property_id, first_time_arrival_date, stay_no) AS
(
SELECT s.customer_id
, s.property_id
, s.arrival_date AS first_time_arrival_date
, ROW_NUMBER() OVER (PARTITION BY s.customer_id, s.property_id ORDER BY s.arrival_date) stay_no
FROM stays s
)
SELECT c.surname AS customer_surname
, c.name AS customer_name
, p.property_name
, s.first_time_arrival_date
FROM customer c
INNER
JOIN first_stays s
ON s.customer_id = c.customer_id
AND s.stay_no = 1
INNER
JOIN property p
ON p.property_id = s.property_id
The first part WITH first_stays is a CTE (Common Table Expression, called subquery factoring in Oracle) that will number the stays for each pair (customer_id, property_id) ordered by the arrival date using a window function ROW_NUMBER(). Then just join those values to the customer and property tables to get their names or whatever, and apply stay_no = 1 (first stay) condition.
If I understand the question correctly, this is not a complicated query:
select c.*
from c join
(select s.customer_id
from stays s
group by s.customer_id
having count(*) = 1
) s
on s.customer_id = c.customer_id;

how to check if the value of column is inside a provided valid list from another query

I have two queries the first one give me the following information:
SELECT
x.id_receipt,
x.id_employee,
x.product_id,
x.receipt_date,
bb.product_name,
from receipt x
Left join product bb on x.id_product=bb.id
The next one is :
SELECT
a.id,
v.allowed_product
from employee a
Left join valid_product v on a.id=v.id_employee
For each employee , there is a list of valid product.
How can I check in the first query if each shopping was an allowed shopping for the employee?
I want to check if the bb.product_name is inside the list of allowed product for each employee from the second query
I think you can just do this with an additional join:
select x.id_receipt, x.id_employee, x.product_id, x.receipt_date,
bb.product_name,
from receipt x join
product bb
on x.id_product = bb.id join
valid_product vp
on vp.id_employee = x.id_employee and vp.allowed_product = bb.id;
Because the products have to match, there is no need for a left join.
I think you can use the WHERE clause to specify what you are looking for. Like:
SELECT bb.product_name
FROM receipt as x, employee as a
WHERE x.bb.product_name = a.allowed_product

Need to select only patients who have not specific codes

I have here an issue in this sql - it will give me the rows that are not these diagnosis codes. But a patient can have them as well.
I need patients who do not have these 3 codes
V72.31', 'Z01.411', 'Z01.419' at all.
SELECT distinct "Vouchers"."Patient_ID"
FROM (("Ntier_70751"."PM"."Service_Diagnoses" "Service_Diagnoses"
INNER JOIN "Ntier_70751"."PM"."Services" "Services"
ON "Service_Diagnoses"."Service_ID"="Services"."Service_ID")
INNER JOIN "Ntier_70751"."PM"."Diagnosis_Codes" "Diagnosis_Codes"
ON "Service_Diagnoses"."Diagnosis_Code_ID"="Diagnosis_Codes"."Diagnosis_Code_ID")
INNER JOIN "Ntier_70751"."PM"."Vouchers" "Vouchers" ON "Services"."Voucher_ID"="Vouchers"."Voucher_ID"
WHERE "Diagnosis_Codes"."Diagnosis_Code" not in ('V72.31', 'Z01.411', 'Z01.419')
Your desired outcome is unclear.
This will show patients who have your "invalid" codes, so long as they have at least one code that is not in your exclusion list:
SELECT DISTINCT
v.Patient_ID
FROM
Ntier_70751.PM.Service_Diagnoses sd
INNER JOIN Ntier_70751.PM.Services s
ON sd.Service_ID = s.Service_ID
INNER JOIN Ntier_70751.PM.Diagnosis_Codes dc
ON sd.Diagnosis_Code_ID = dc.Diagnosis_Code_ID
AND dc.Diagnosis_Code not in ('V72.31', 'Z01.411', 'Z01.419')
INNER JOIN Ntier_70751.PM.Vouchers v
ON s.Voucher_ID= v.Voucher_ID
And this one will exclude patients who have at least one of the "invalid" codes (regardless of what other "valid" codes they may have):
SELECT DISTINCT
v.Patient_ID
FROM
Ntier_70751.PM.Vouchers v
WHERE
v.Patient_ID NOT IN
(
SELECT DISTINCT
v.Patient_ID
FROM
Ntier_70751.PM.Service_Diagnoses sd
INNER JOIN Ntier_70751.PM.Services s
ON sd.Service_ID = s.Service_ID
INNER JOIN Ntier_70751.PM.Diagnosis_Codes dc
ON sd.Diagnosis_Code_ID = dc.Diagnosis_Code_ID
AND dc.Diagnosis_Code in ('V72.31', 'Z01.411', 'Z01.419')
INNER JOIN Ntier_70751.PM.Vouchers v
ON s.Voucher_ID= v.Voucher_ID
)
Why are you attempting to do this umpteen-way join? I'm sure there's a far more efficient way to do things. We need, however, a more precise description of what you're trying to achieve.
The problem is the scope to which the restricting WHERE clause is applied. You are essentially saying
SELECT . . .
FROM (THIS
JOIN THAT
JOIN (THEOTHERONE WHERE . . .))
when what you actually need is:
SELECT . . .
FROM (THIS JOIN THAT JOIN THEOTHERONE)
WHERE . . .
By constructing the multi-way join, you are picking up and tacking on other tuples that may contain those unwanted diagnosis codes. Do your selection ("selection" means WHERE; SELECT is actually "projection" [poor choice of keywords from the creators of SQL) at the last possible moment.
Here's a suggestion. Today, you want to reject records where the diagnosis codes match, say, A, B, or C; tomorrow you may want to ALSO reject records where the diagnosis codes match P or Q. You should GENERALIZE this to make it TABLE-DRIVEN: create a second table
CREATE TABLE REJECTION_CATEGORY( CATEG, DIAGN_CODE )
PRIMARY KEY( CATEG, DIAGN_CODE )
and initialize it with the following query:
INSERT INTO REJECTION_CATEGORY VALUES( 1, 'V72.31 ),
VALUE ( 1, 'Z01.411' ),
VALUES( 1, 'Z01.419' )
then you can change your first query to:
SELECT . . .
FROM (join-of-this-and-that)
WHERE DIAGNOSIS_CODE NOT IN (
SELECT DIAGN_CODE
FROM REJECTION_CATEGORY
WHERE CATEG = 1)
and tomorrow's query, which rejects a COMPLETELY DIFFERENT set of diagnosis codes, just changes the last line but one to read WHERE CATEG = 2.

Eliminate duplicate rows from query output

I have a large SELECT query with multiple JOINS and WHERE clauses. Despite specifying DISTINCT (also have tried GROUP BY) - there are duplicate rows returned. I am assuming this is because the query selects several IDs from several tables. At any rate, I would like to know if there is a way to remove duplicate rows from a result set, based on a condition.
I am looking to remove duplicates from results if x.ID appears more than once. The duplicate rows all appear grouped together with the same IDs.
Query:
SELECT e.Employee_ID, ce.CC_ID as CCID, e.Manager_ID, e.First_Name, e.Last_Name,,e.Last_Login,
e.Date_Created AS Date_Created, e.Employee_Password AS Password,e.EmpLogin
ISNULL((SELECT TOP 1 1 FROM Gift g
JOIN Type t ON g.TypeID = t.TypeID AND t.Code = 'Reb'
WHERE g.Manager_ID = e.Manager_ID),0) RebGift,
i.DateCreated as ImportDate
FROM #EmployeeTemp ct
JOIN dbo.Employee c ON ct.Employee_ID = e.Employee_ID
INNER JOIN dbo.Manager p ON e.Manager_ID = m.Manager_ID
LEFT JOIN EmployeeImp i ON e.Employee_ID = i.Employee_ID AND i.Active = 1
INNER JOIN CreditCard_Updates cc ON m.Manager_ID = ce.Manager_ID
LEFT JOIN Manager m2 ON m2.Manager_ID = ce.Modified_By
WHERE ce.CCType ='R' AND m.isT4L = 1
AND CHARINDEX(e.first_name, Selected_Emp) > 0
AND ce.Processed_Flag = #isProcessed
I don't have enough reputation to add a comment, so I'll just try to help you in an answer proper (even though this is more of a comment).
It seems like what you want to do is select distinctly on just one column.
Here are some answers which look like that:
SELECT DISTINCT on one column
How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?