NOT EXIST in a subquery, joined back to separate table - sql

Running a report to figure out which parts in our system have not had an order within a certain period of time. Other minor aspects to this report, this is the main area I'm struggling. Best I could figure out is getting a list of parts that HAVE had orders during this time then comparing it back against the other table, but either my joins or subqueries are working correctly.
Does NOT EXIST work like this?
SELECT i.customer_no AS CustNumber,
i.part_no AS PartNumber,
p.cpt_prog_mat
FROM fit_part_info i
INNER JOIN fit_part_forecast f ON f.part_info_id = i.id
INNER JOIN orrcpt_rec p ON i.part_no = p.cpt_cus_part_no
WHERE (accounting_period = "201911" AND cpt_prog_mat = "Y") OR
(accounting_period = "201912" AND cpt_prog_mat = "Y") OR
(accounting_period = "202001" AND cpt_prog_mat = "Y") OR
(accounting_period = "202002" AND cpt_prog_mat = "Y") AND
NOT EXISTS (SELECT DISTINCT(i.part_no)
FROM INNER JOIN ortord_rec o ON i.part_no = o.ord_cus_part_no
WHERE (o.ord_comp_dt < 20191126 AND o.ord_comp_dt > 20190925 AND o.ord_cus_part_no <> ""))
GROUP BY i.part_no, i.customer_no, p.cpt_prog_mat
ORDER BY i.part_no;

it looks like you are missing the initial table name in the subselect.
try
NOT EXISTS (
SELECT 1
FROM fit_part_info i
INNER JOIN ortord_rec o ON i.part_no = o.ord_cus_part_no
WHERE
o.ord_comp_dt < 20191126
AND o.ord_comp_dt > 20190925
AND o.ord_cus_part_no <> ""
)
btw, you can use select 1 bc you don't actually need to select something if you are just checking for its existence

Related

Speed up SQL query performance with nested queries

Could anyone help me speed this query up? It currently take 17 minutes to run but does return the correct data and it populates a subform in MS Access. Functions in the rest of the VBA are declared as long to try to speed up more.
Here's the full query:
SELECT lots of things
FROM (((((((((((((((ngstest
INNER JOIN patients
ON ngstest.internalpatientid = patients.internalpatientid)
INNER JOIN referral
ON ngstest.referralid = referral.referralid)
INNER JOIN checker
ON ngstest.bookby = checker.check1id)
INNER JOIN ngspanel
ON ngstest.ngspanelid = ngspanel.ngspanelid)
LEFT JOIN ngspanel AS ngspanel_1
ON ngstest.ngspanelid_b = ngspanel_1.ngspanelid)
INNER JOIN status
ON ngstest.statusid = status.statusid)
INNER JOIN dbo_patient_table
ON patients.patientid = dbo_patient_table.patienttrustid)
LEFT JOIN dna
ON ngstest.dna = dna.dnanumber)
INNER JOIN status AS status_1
ON patients.s_statusoverall = status_1.statusid)
LEFT JOIN gw_gendertable
ON dbo_patient_table.genderid = gw_gendertable.genderid)
LEFT JOIN ngswesbatch
ON ngstest.wesbatch = ngswesbatch.ngswesbatchid)
LEFT JOIN checker AS checker_1
ON ngstest.check1id = checker_1.check1id)
LEFT JOIN checker AS checker_2
ON ngstest.check2id = checker_2.check1id)
LEFT JOIN checker AS checker_3
ON ngstest.check3id = checker_3.check1id)
LEFT JOIN ngspanel AS ngspanel_2
ON ngstest.ngspanelid_c = ngspanel_2.ngspanelid)
LEFT JOIN checker AS checker_4
ON ngstest.check4id = checker_4.check1id
WHERE ((ngstest.referralid IN
(SELECT referralid FROM referral
WHERE grouptypeid = 14)
AND ngstest.ngstestid IN
(SELECT ngstest.ngstestid
FROM ngsanalysis
INNER JOIN ngstest
ON ngsanalysis.ngstestid = ngstest.ngstestid
WHERE ngsanalysis.pedigree = 3302) )
AND status.statusid = 1202218800)
ORDER BY ngstest.priority,
ngstest.daterequested;
The two nested queries are strings from elsewhere in the code so are called in the vba as " & includereferralls & " And " & ParentsStatusesFilter & "
They are:
ParentsStatusesFilter = "NGSTest.NGSTestID in
(SELECT NGSTest.NGSTestID
FROM NGSAnalysis
INNER JOIN NGSTest
ON NGSAnalysis.NGSTestID = NGSTest.NGSTestID
WHERE NGSAnalysis.Pedigree IN (3302,3303,3304)"
And
includereferrals = "NGSTest.ReferralID
(SELECT referralid FROM referral WHERE referral.grouptypeid = 14)"
The query needs to remain readable (and therefore editable) so can't use things like Distinct, Group By or contain any Unions. Have tried Exists instead of In for the nested queries but that stops it from actually filtering the results.
WHERE EXISTS (SELECT NGSTest.NGSTestID
FROM NGSAnalysis
INNER JOIN NGSTest
ON NGSAnalysis.NGSTestID = NGSTest.NGSTestID
WHERE NGSAnalysis.Pedigree IN (3302,3303,3304)
So the exist clause you have there isn't tied to the outer query which would run similar to just added 1 = 1 to the where clause. I took your where clause and converted it. It should look something like this...
WHERE EXISTS (
SELECT referralid
FROM referral
WHERE grouptypeid = 14 AND ngstest.referralid = referral.referralid)
AND EXISTS (
SELECT ngsanalysis.ngstestid
FROM ngsanalysis
WHERE ngsanalysis.pedigree IN (3302,3303,3304) AND ngstest.ngstestid = ngsanalysis.ngstestid
)
AND status.statusid = 1202218800
Adding exists will speed it up a bit, but the the bulk of the slowness is the left joins. Access does not handle the left joins as well as SQL Server does. Change all your joins to inner joins and you will see the query runs very fast. This is obviously not ideal since some relationships are optional. What I have done to get around this is add a default record that replaces a null relationship.
Here is what that looks like for you: In the checker table you could add a record that represents a null value. So put a record into the checker table with check1id of -1 or 0. Then default check1id, check2id, check3id on ngstest to -1 or 0. You will need to do that type of thing for all tables you need to left join on.

How do I fix the syntax of a sub query with joins?

I have the following query:
SELECT tours_atp.NAME_T, today_atp.TOUR, today_atp.ID1, odds_atp.K1, today_atp.ID2, odds_atp.K2
FROM (players_atp INNER JOIN (players_atp AS players_atp_1 INNER JOIN (today_atp INNER JOIN odds_atp ON (today_atp.TOUR = odds_atp.ID_T_O) AND (today_atp.ID1 = odds_atp.ID1_O) AND (today_atp.ID2 = odds_atp.ID2_O) AND (today_atp.ROUND = odds_atp.ID_R_O)) ON players_atp_1.ID_P = today_atp.ID2) ON players_atp.ID_P = today_atp.ID1) INNER JOIN tours_atp ON today_atp.TOUR = tours_atp.ID_T
WHERE (((tours_atp.RANK_T) Between 1 And 4) AND ((today_atp.RESULT)="") AND ((players_atp.NAME_P) Not Like "*/*") AND ((players_atp_1.NAME_P) Not Like "*/*") AND ((odds_atp.ID_B_O)=2))
ORDER BY tours_atp.NAME_T;
I'd like to add a field to this query that provides me with the sum of a field in another table (FS) with a few criteria applied.
I've been able to build a stand alone query to get the sum of FS by ID_T as follows:
SELECT tbl_Ts_base_atp.ID_T, Sum(tbl_Ts_mkv_atp.FS) AS SumOfFS
FROM tbl_Ts_base_atp INNER JOIN tbl_Ts_mkv_atp ON tbl_Ts_base_atp.ID_Ts = tbl_Ts_mkv_atp.ID_Ts
WHERE (((tbl_Ts_base_atp.DATE_T)>Date()-2000 And (tbl_Ts_base_atp.DATE_T)<Date()))
GROUP BY tbl_Ts_base_atp.ID_T, tbl_Ts_mkv_atp.ID_Ts;
I now want to match up the sum of FS from the second query to the records of the first query by ID_T. I realise I need to do this using a sub query. I'm confident using these when there's only one table but I consistently get 'syntax errors' when there are joins.
I simplified the first query down to remove all the WHERE conditions so it was easier for me to try and error check but no luck. I guess the resulting SQL will also be easier for you guys to follow:
SELECT today_atp.TOUR, (SELECT Sum(tbl_Ts_mkv_atp.FS)
FROM tbl_Ts_mkv_atp INNER JOIN (tbl_Ts_base_atp INNER JOIN today_atp ON tbl_Ts_base_atp.ID_T = today_atp.TOUR) ON tbl_Ts_mkv_atp.ID_Ts = tbl_Ts_base_atp.ID_Ts AS tt
WHERE tt.DATE_T>Date()-2000 And tt.DATE_T<Date() AND tt.TOUR=today_atp.TOUR
ORDER BY tt.DATE_T) AS SumOfFS
FROM today_atp
Can you spot where I'm going wrong? My hunch is that the issue is in the FROM line of the sub query but I'm not sure. Thanks in advance.
It's difficult to advise an appropriate solution without knowledge of how the database tables relate to one another, but assuming that I've correctly understood what you are looking to achieve, you might wish to try the following solution:
select
tours_atp.name_t,
today_atp.tour,
today_atp.id1,
odds_atp.k1,
today_atp.id2,
odds_atp.k2,
subq.sumoffs
from
(
(
(
(
today_atp inner join odds_atp on
today_atp.tour = odds_atp.id_t_o and
today_atp.id1 = odds_atp.id1_o and
today_atp.id2 = odds_atp.id2_o and
today_atp.round = odds_atp.id_r_o
)
inner join players_atp as players_atp_1 on
players_atp_1.id_p = today_atp.id2
)
inner join players_atp on
players_atp.id_p = today_atp.id1
)
inner join tours_atp on
today_atp.tour = tours_atp.id_t
)
inner join
(
select
tbl_ts_base_atp.id_t,
sum(tbl_ts_mkv_atp.fs) as sumoffs
from
tbl_ts_base_atp inner join tbl_ts_mkv_atp on
tbl_ts_base_atp.id_ts = tbl_ts_mkv_atp.id_ts
where
tbl_ts_base_atp.date_t > date()-2000 and tbl_ts_base_atp.date_t < date()
group by
tbl_ts_base_atp.id_t
) subq on
tours_atp.tour = subq.id_t
where
(tours_atp.rank_t between 1 and 4) and
today_atp.result = "" and
players_atp.name_p not like "*/*" and
players_atp_1.name_p not like "*/*" and
odds_atp.id_b_o = 2
order by
tours_atp.name_t;

SQL Query with counts only returning equivalent counts

I have a query that consists of 1 table and 2 sub queries. The table being a listing of all customers, 1 sub query is a listing all of the quotes given over a period of time for customers and the other sub query is a listing of all of the orders booked for a customer over the same period of time. What I am trying to do is return a result set that is a customer, the number of quotes given, and the number of orders booked over a given period of time. However what I am returning is only a listening of customers over the period of time that have an equivalent quote and order count. I feel like I am missing something obvious within the context of the query but I am unable to figure it out. Any help would be appreciated. Thank you.
Result Set should look like this
Customer-------Quotes-------Orders Placed
aaa----------------4----------------4
bbb----------------9----------------18
ccc----------------18----------------9
select
[Customer2].[Name] as [Customer2_Name],
(count( Quotes.UD03_Key3 )) as [Calculated_CustomerQuotes],
(count( Customer_Bookings.OrderHed_OrderNum )) as [Calculated_CustomerBookings]
from Erp.Customer as Customer2
left join (select
[UD03].[Key3] as [UD03_Key3],
[UD03].[Key4] as [UD03_Key4],
[UD03].[Key1] as [UD03_Key1],
[UD03].[Date02] as [UD03_Date02]
from Ice.UD03 as UD03
inner join Ice.UD02 as UD02 on
UD03.Company = UD02.Company
And
CAST(CAST(UD03.Number09 AS INT) AS VARCHAR(30)) = UD02.Key1
left outer join Erp.Customer as Customer on
UD03.Company = Customer.Company
And
UD03.Key1 = Customer.Name
left outer join Erp.SalesTer as SalesTer on
Customer.Company = SalesTer.Company
And
Customer.TerritoryID = SalesTer.TerritoryID
left outer join Erp.CustGrup as CustGrup on
Customer.Company = CustGrup.Company
And
Customer.GroupCode = CustGrup.GroupCode
where (UD03.Key3 <> '0')) as Quotes on
Customer2.Name = Quotes.UD03_Key1
left join (select
[Customer1].[Name] as [Customer1_Name],
[OrderHed].[OrderNum] as [OrderHed_OrderNum],
[OrderDtl].[OrderLine] as [OrderDtl_OrderLine],
[OrderHed].[OrderDate] as [OrderHed_OrderDate]
from Erp.OrderHed as OrderHed
inner join Erp.Customer as Customer1 on
OrderHed.Company = Customer1.Company
And
OrderHed.BTCustNum = Customer1.CustNum
inner join Erp.OrderDtl as OrderDtl on
OrderHed.Company = OrderDtl.Company
And
OrderHed.OrderNum = OrderDtl.OrderNum) as Customer_Bookings on
Customer2.Name = Customer_Bookings.Customer1_Name
where Quotes.UD03_Date02 >= '5/15/2018' and Quotes.UD03_Date02 <= '5/15/2018' and Customer_Bookings.OrderHed_OrderDate >='5/15/2018' and Customer_Bookings.OrderHed_OrderDate <= '5/15/2018'
group by [Customer2].[Name]
You have several problems going on here. The first problem is your code is so poorly formatted it is user hostile to look at. Then you have left joins being logically treated an inner joins because of the where clause. You also have date literal strings in language specific format. This should always be the ANSI format YYYYMMDD. But in your case your two predicates are contradicting each other. You have where UD03_Date02 is simultaneously greater than and less than the same date. Thankfully you have =. But if your column is a datetime you have prevented any rows from being returned again (the first being your where clause). You have this same incorrect date logic and join in the second subquery as well.
Here is what your query might look like with some formatting so you can see what is going on. Please note I fixed the logical join issue. You still have the date problems because I don't know what you are trying to accomplish there.
select
[Customer2].[Name] as [Customer2_Name],
count(Quotes.UD03_Key3) as [Calculated_CustomerQuotes],
count(Customer_Bookings.OrderHed_OrderNum) as [Calculated_CustomerBookings]
from Erp.Customer as Customer2
left join
(
select
[UD03].[Key3] as [UD03_Key3],
[UD03].[Key4] as [UD03_Key4],
[UD03].[Key1] as [UD03_Key1],
[UD03].[Date02] as [UD03_Date02]
from Ice.UD03 as UD03
inner join Ice.UD02 as UD02 on UD03.Company = UD02.Company
And CAST(CAST(UD03.Number09 AS INT) AS VARCHAR(30)) = UD02.Key1
left outer join Erp.Customer as Customer on UD03.Company = Customer.Company
And UD03.Key1 = Customer.Name
left outer join Erp.SalesTer as SalesTer on Customer.Company = SalesTer.Company
And Customer.TerritoryID = SalesTer.TerritoryID
left outer join Erp.CustGrup as CustGrup on Customer.Company = CustGrup.Company
And Customer.GroupCode = CustGrup.GroupCode
where UD03.Key3 <> '0'
) as Quotes on Customer2.Name = Quotes.UD03_Key1
and Quotes.UD03_Date02 >= '20180515'
and Quotes.UD03_Date02 <= '20180515'
left join
(
select
[Customer1].[Name] as [Customer1_Name],
[OrderHed].[OrderNum] as [OrderHed_OrderNum],
[OrderDtl].[OrderLine] as [OrderDtl_OrderLine],
[OrderHed].[OrderDate] as [OrderHed_OrderDate]
from Erp.OrderHed as OrderHed
inner join Erp.Customer as Customer1 on OrderHed.Company = Customer1.Company
And OrderHed.BTCustNum = Customer1.CustNum
inner join Erp.OrderDtl as OrderDtl on OrderHed.Company = OrderDtl.Company
And OrderHed.OrderNum = OrderDtl.OrderNum
) as Customer_Bookings on Customer2.Name = Customer_Bookings.Customer1_Name
and Customer_Bookings.OrderHed_OrderDate >= '20180515'
and Customer_Bookings.OrderHed_OrderDate <= '20180515'
group by [Customer2].[Name]
COUNT() will just give you the number of records. You'd expect this two result columns to be equal. Try structuring it like this:
SUM(CASE WHEN Quote.UD03_Key1 IS NOT NULL THEN 1 ELSE 0 END) AS QuoteCount,
SUM(CASE WHEN Customer_Bookings.Customer1_Name IS NOT NULL THEN 1 ELSE 0 END) AS custBookingCount

SQL database - joining, but with nulls

I'm having trouble with the following view (using SQL Server 2008). Basically, I've got three tables - tbl_PhysicalAsset (PA), tbl_Operations (OP) and tbl_Schedules (SC). One record in PA relates to many in OP, and one in OP to many in SC. The PA and OP are irrelevant here really, but the SC one is giving me problems.
I'm writing a query which displays the maximum done date from SC (basically done by grouping on the field which relates back to the OP, and the max of the done date), which is fair enough. I've also had to try and get the "Issues" column (a varchar) from the SC table too, in case there were issues. This is where it's falling down - some of the things in SC will not have a "done date" filled in (ie it will be null), but we still need to display the information.
The following is where I've got to:
SELECT TOP (100) PERCENT
dbo.tbl_PhysicalAsset.FKID_Contract, dbo.tbl_PhysicalAsset.MyLevel,
dbo.tbl_PhysicalAsset.L1_Name, dbo.tbl_PhysicalAsset.L2_Name,
dbo.tbl_PhysicalAsset.L3_Name, s1.FKID_Operation,
dbo.tbl_PhysicalAsset.Deleted AS Del1,
dbo.tbl_Operations.Deleted AS Del2, s1.Deleted AS Del3,
s1.SchedDone, s1.Issues
FROM
dbo.tbl_Schedules AS s1
INNER JOIN
dbo.tbl_Operations
INNER JOIN
dbo.tbl_PhysicalAsset ON dbo.tbl_Operations.FKID_PhysicalAsset = dbo.tbl_PhysicalAsset.PKID_PhysicalAsset
INNER JOIN
(SELECT
MAX(SchedDone) AS SchedDone, FKID_Operation
FROM
dbo.tbl_Schedules
GROUP BY
FKID_Operation) AS s2 ON dbo.tbl_Operations.PKID_Operation = s2.FKID_Operation ON s1.FKID_Operation = s2.FKID_Operation AND s1.SchedDone = s2.SchedDone
WHERE
(dbo.tbl_PhysicalAsset.FKID_Contract = 6)
AND (dbo.tbl_PhysicalAsset.MyLevel = 3)
AND (s1.FKID_Operation IS NOT NULL)
AND (dbo.tbl_PhysicalAsset.Deleted = 0)
AND (dbo.tbl_Operations.Deleted = 0)
AND (s1.Deleted = 0)
ORDER BY
dbo.tbl_PhysicalAsset.L1_Name, dbo.tbl_PhysicalAsset.L2_Name,
dbo.tbl_PhysicalAsset.L3_Name
As I say, if a record is missing a max done date then all information regarding it doesn't appear.
I've tried using left joins (and even right joins) but this makes no difference (and SQL Server normally tries to be helpful and makes them outer joins).
try now ....
SELECT PA.FKID_Contract
, PA.MyLevel
, PA.L1_Name
, PA.L2_Name
, PA.L3_Name
, s1.FKID_Operation
, PA.Deleted AS Del1
, OPS.Deleted AS Del2
, s1.Deleted AS Del3
, s1.SchedDone
, s1.Issues
FROM dbo.tbl_Schedules AS s1
INNER JOIN dbo.tbl_Operations OPS ON OPS.PKID_Operation = s1.FKID_Operation
INNER JOIN dbo.tbl_PhysicalAsset PA ON OPS.FKID_PhysicalAsset = PA.PKID_PhysicalAsset
INNER JOIN
(SELECT MAX(SchedDone) AS SchedDone, FKID_Operation
FROM dbo.tbl_Schedules
GROUP BY FKID_Operation) AS s2
ON s1.FKID_Operation = s2.FKID_Operation
AND s1.SchedDone = s2.SchedDone
WHERE (PA.FKID_Contract = 6)
AND (PA.MyLevel = 3)
AND (s1.FKID_Operation IS NOT NULL)
AND (PA.Deleted = 0)
AND (OPS.Deleted = 0)
AND (s1.Deleted = 0)
ORDER BY PA.L1_Name, PA.L2_Name, PA.L3_Name
Okay, this was my bad. I made a mistake with some of my deleted fields. Turns out that the original solution was pretty much spot-on and I was looking for anything that contained a False in the Deleted column (in my case, s1). However, I hadn't thought that, if a record can't be found, it will of course not have a False. So I moved which table I was checking for the Deleted schedules to s2 and just used the Schedules table:
SELECT TOP (100) PERCENT dbo.tbl_PhysicalAsset.FKID_Contract, dbo.tbl_PhysicalAsset.MyLevel, dbo.tbl_PhysicalAsset.L1_Name, dbo.tbl_PhysicalAsset.L2_Name,
dbo.tbl_PhysicalAsset.L3_Name, dbo.tbl_PhysicalAsset.Deleted AS Del1, dbo.tbl_Operations.Deleted AS Del2, s2.SchedDone, s2.Deleted, tbl_Schedules_1.Issues,
tbl_Schedules_1.Deleted AS Expr1
FROM dbo.tbl_Operations INNER JOIN
dbo.tbl_PhysicalAsset ON dbo.tbl_Operations.FKID_PhysicalAsset = dbo.tbl_PhysicalAsset.PKID_PhysicalAsset INNER JOIN
(SELECT MAX(SchedDone) AS SchedDone, FKID_Operation, Deleted
FROM dbo.tbl_Schedules
GROUP BY FKID_Operation, Deleted) AS s2 ON dbo.tbl_Operations.PKID_Operation = s2.FKID_Operation LEFT OUTER JOIN
dbo.tbl_Schedules AS tbl_Schedules_1 ON s2.SchedDone = tbl_Schedules_1.SchedDone AND s2.FKID_Operation = tbl_Schedules_1.FKID_Operation
WHERE (dbo.tbl_PhysicalAsset.FKID_Contract = 6) AND (dbo.tbl_PhysicalAsset.MyLevel = 3) AND (dbo.tbl_PhysicalAsset.Deleted = 0) AND (dbo.tbl_Operations.Deleted = 0)
AND (s2.Deleted = 0)
ORDER BY dbo.tbl_PhysicalAsset.L1_Name, dbo.tbl_PhysicalAsset.L2_Name, dbo.tbl_PhysicalAsset.L3_Name

Replace IN with EXISTS or COUNT. How to do it. What is missing here?

I am using IN keyword in the query in the middle of a section. Since I am using nested query and want to replace In with Exists due to performance issues that my seniors have told me might arise.
Am I missing some column, what you are looking for in this query. This query contain some aliases for readibility.
How can I remove it.
SELECT TX.PK_MAP_ID AS MAP_ID
, MG.PK_GUEST_ID AS Guest_Id
, MG.FIRST_NAME
, H.PK_CATEGORY_ID AS Preference_Id
, H.DESCRIPTION AS Preference_Name
, H.FK_CATEGORY_ID AS Parent_Id
, H.IMMEDIATE_PARENT AS Parent_Name
, H.Department_ID
, H.Department_Name
, H.ID_PATH, H.DESC_PATH
FROM
dbo.M_GUEST AS MG
LEFT OUTER JOIN
dbo.TX_MAP_GUEST_PREFERENCE AS TX
ON
(MG.PK_GUEST_ID = TX.FK_GUEST_ID)
LEFT OUTER JOIN
dbo.GetHierarchy_Table AS H
ON
(TX.FK_CATEGORY_ID = H.PK_CATEGORY_ID)
WHERE
(MG.IS_ACTIVE = 1)
AND
(TX.IS_ACTIVE = 1)
AND
(H.Department_ID IN -----How to remove this IN operator with EXISTS or Count()
(
SELECT C.PK_CATEGORY_ID AS DepartmentId
FROM
dbo.TX_MAP_DEPARTMENT_OPERATOR AS D
INNER JOIN
dbo.M_OPERATOR AS M
ON
(D.FK_OPERATOR_ID = M.PK_OPERATOR_ID)
AND
(D.IS_ACTIVE = M.IS_ACTIVE)
INNER JOIN
dbo.L_USER_ROLE AS R
ON
(M.FK_ROLE_ID = R.PK_ROLE_ID)
AND
(M.IS_ACTIVE = R.IS_ACTIVE)
INNER JOIN
dbo.L_CATEGORY_TYPE AS C
ON
(D.FK_DEPARTMENT_ID = C.PK_CATEGORY_ID)
AND
(D.IS_ACTIVE = C.IS_ACTIVE)
WHERE
(D.IS_ACTIVE = 1)
AND
(M.IS_ACTIVE = 1)
AND
(R.IS_ACTIVE = 1)
AND
(C.IS_ACTIVE = 1)
)--END INNER QUERY
)--END Condition
What new problems might I get if I replace IN with EXISTS or COUNT ?
Basically, as I understand your question, you are asking how can I replace this:
where H.department_id in (select departmentid from...)
with this:
where exists (select...)
or this:
where (select count(*) from ...) > 1
It is fairly straight forward. One method might be this:
WHERE...
AND EXISTS (select c.pk_category_id
from tx_map_department_operator d
inner join m_operator as m
on d.fk_operator_id = m.pk_operator_id
inner join l_user_role l
on m.fk_role_id = r.pk_role_id
inner join l_category_type c
on d.fk_department_id = c.pk_category_id
where h.department_id = c.pk_category_id
and d.is_active = 1
and m.is_active = 1
and r.is_active = 1
and c.is_active = 1
)
I removed the extra joins on is_active because they were redundant. You should test how it runs with your indexes, because that might have been faster. I doubt it though. But it is worth comparing whether it is faster to add the join clause (join on ... and x.is_active=y.is_active) or to check in the where clause (x.is_active=1 and y.is_active=1 and z.is_active=1...)
And I'd recommend you just use exists, instead of count(*), because I know that exists should stop after finding 1 row, whereas count probably continues to execute until done, and then compares to your reference value (count > 1).
As an aside, that is a strange column naming standard you have. Do you really have PK prefixes for the primary keys, and FK prefixes for the foreign keys? I have never seen that.