SQL NOT exists conditional - sql

I have three tables as described below:
dbo.ServiceEntry
ID RunLogEntry Reconciled
1 0 1
2 4 1
3 5 1
dbo.ServiceEntryPart
ID ServiceEntryID PartId ServiceEntryTypeID
1 1 3 1
2 2 4 2
3 2 4 1,2
dbo.Part
ID Desc Active (bitfield)
3 xyz 1
4 abc 1
Query as follows:
SELECT *
FROM ServiceEntry AS S
WHERE (S.RunLogEntryID is not null) AND (S.Reconciled=#ReconciledValue)
AND EXISTS (SELECT ServiceEntryID
FROM ServiceEntryPart SEP
JOIN Part on SEP.PartID = Part.ID
WHERE ((#ActivePart = 0 AND Part.Active is not null)
OR (#ActivePart = 1 and Part.Active = 0))
AND (#ServiceTypes is null
OR CHARINDEX(','+cast(SEP.ServiceTypeIDs as varchar(255))+',',','+#ServiceTypes+',') > 0))
OR (NOT EXISTS (SELECT ServiceEntryID
FROM ServiceEntryPart SEP
JOIN Part on SEP.PartID = Part.ID))
service entry has some records which contain runlogentry id of 0. If the runlogentryid value in service entry table is 0 then there will be no service entry part record for that service entry. Thats why I split them into two as you would notice from the query for example exists and not exists. the exists statement takes care of all service entries which have service entry parts and for these the filters will be applicable. If the filters have values then the not exist block will be not be needed because filters servicetypeids and activepart are for only records which have service entry parts.
So in other words if no params are passed the first exists block fetches service entries which have service parts and the not exists fetches service entries which have runlogentry id of 0 OR NOT null. This works great as it is. The problem is when the params are passed I would need to exclude the serviceentries which do not have service entry parts and when they are present I do not get the rigth results. I hope I did an okay job explaining the problem..Please help

Without trying to understand the rest of your SQL, if all you want to do is avoid the NOT EXISTS clause when your parameters are null you can do something like this.
SELECT *
FROM ServiceEntry AS S
JOIN
WHERE (S.RunLogEntryID is not null) AND (S.Reconciled=#ReconciledValue)
AND EXISTS (SELECT ServiceEntryID
FROM ServiceEntryPart SEP
JOIN Part on SEP.PartID = Part.ID
WHERE ((#ActivePart = 0 AND Part.Active is not null)
OR (#ActivePart = 1 and Part.Active = 0))
AND (#ServiceTypes is null
OR CHARINDEX(','+cast(SEP.ServiceTypeIDs as varchar(255))+',',','+#ServiceTypes+',') > 0))
OR (#ReconciledValue is null and #ActivePart is null and #ServiceTypes is null
and (NOT EXISTS (SELECT ServiceEntryID
FROM ServiceEntryPart SEP
JOIN Part on SEP.PartID = Part.ID)))

This probably isn't exactly what you want, to be honest the query seems all over the place.
You're probably looking for an active part filter like '(#ActivePart is null or #ActivePart = Part.Active)'. Your exists is implicitly taken care of by an inner join. A query that I believe is close to what you're looking for is below.
select *
FROM ServiceEntry AS S
INNER JOIN ServiceEntryPart AS SEP ON SEP.ServiceEntryID = S.ServiceEntryID
INNER JOIN Part AS P ON P.PartID = SEP.PartID
WHERE S.RunLogEntryID is not null
and S.Reconciled = #ReconciledValue
and (#ActivePart is null or #ActivePart = Part.Active)
and (#ServiceTypes is null or charindex(','+cast(SEP.ServiceTypeIDs as varchar(255))+',',','+#ServiceTypes+',') > 0

I can't be sure because I don't have the business definitions of your columns, but I suspect your conditions dealing with Part.Active are wrong. I would expect the values to be 0 or 1, not NULL or 0. So I should think the test should return TRUE when the parameter is NULL or the parameter matches the column.
Your CHARINDEX function has the parameters reversed.
You need additional parentheses to get the correct order of operation and your OR NOT EXISTS clause needs additional conditions to make it only true if the parameters are NULL.
I believe the following is much closer to what you are looking for. But I am worried about the ServiceTypes test. It will only work reliably if the parameter contains a single ServiceTypeID. If it contains multiple IDs it may not work. For example, I would think a parameter value of '1,3' should match a list of '1,2,3', but it won't.
SELECT *
FROM ServiceEntry AS S
WHERE (S.RunLogEntryID IS NOT NULL)
AND (S.Reconciled=#ReconciledValue)
AND( EXISTS(
SELECT ServiceEntryID
FROM ServiceEntryPart SEP
JOIN Part ON SEP.PartID = Part.ID
WHERE( #ActivePart IS NULL
OR #ActivePart = Part.Active
)
AND ( #ServiceTypes IS NULL
OR CHARINDEX( ','+#ServiceTypes+',',
','+cast(SEP.ServiceTypeIDs as varchar(255))+','
) > 0
)
)
OR( #ActivePart IS NULL
AND #ServiceTypes IS NULL
AND NOT EXISTS( SELECT ServiceEntryID
FROM ServiceEntryPart SEP
JOIN Part on SEP.PartID = Part.ID
)
)
)

Related

Join two tables and concatenate same column names in same statement

I have a large raw data table. It's long and I'm trying to sort of transpose it. I'm joining two select statements from within it. As such I get multiple columns with the same name. It's a full outer join and I would like to have the two separate columns of the same name as one column. Since it is an outer join I don't want to pick just one tables column for it either like select t1.c1
Thanks!
SELECT *
FROM (SELECT * FROM [LabData].[dbo].[FermHourlyDCSData] where Attribute='Urea') P
full outer JOIN
(SELECT * FROM [LabData].[dbo].[FermHourlyDCSData] where Attribute='Water to Mash Total Water') FPD ON
P.[TimeStamp] = FPD.[TimeStamp]
and P.Site = FPD.Site
and P.Element = FPD.Element
Actual:
Site Attribute Timestamp Value Site Attribute Timestamp Value
AD Urea 1/1/2019 127 Null Null Null Null
Null Null Null Null AD Water 1/1/2019 7.5
Expected/Desired:
Site Attribute Timestamp Value Value
AD Urea 1/1/2019 127 Null
AD Water 1/1/2019 Null 7.5
Try this, it's not very pretty, but it does work:
SELECT
[Site] = ISNULL(P.[Site], FPD.[Site]),
[Attribute] = ISNULL(P.[Attribute], FPD.[Attribute]),
[Timestamp] = ISNULL(P.[Timestamp], FPD.[Timestamp]),
[Value] = ISNULL(P.[Value], FPD.[Value]),
[Element] =ISNULL(P.[Element], FPD.[Element])
FROM (SELECT * FROM [dbo].[FermHourlyDCSData] where Attribute='Urea') P
full outer JOIN
(SELECT * FROM [dbo].[FermHourlyDCSData] where Attribute='Water to Mash Total Water') FPD ON
P.[TimeStamp] = FPD.[TimeStamp]
and P.Site = FPD.Site
and P.Element = FPD.Element
ISNULL is what you should use for this
ISNULL(p.Site,fpd.Site) as [Site]
Maybe I'm missing something, but you seem to want a much simpler query:
select Site, Attribute, Timestamp,
(case when Attribute = 'Urea' then Value end) as value_u,
(case when Attribute = 'Water to Mash Total Water' then Value end) as value_2
from [LabData].[dbo].[FermHourlyDCSData]
where Attribute in ('Urea', 'Water to Mash Total Water')

Null value is considered an existing value

I have a validation into if conditional like:
IF(EXISTS
(SELECT TOP 1 [TaskAssignationId]
FROM [Task] AS [T]
INNER JOIN #TaskIdTableType AS [TT] ON [T].[TaskId] = [TT].[Id]
))
But it returns NULL value because TaskAssignationId is NULL so in consequence IF condition it's true because it exist with NULL value, but I don't want to consider NULL as a value. How can add an exception of nulls? Regards
If you don't want to include rows where [TaskAssignationId] is null then add that to a WHERE clause.
IF(EXISTS
SELECT TOP 1 [TaskAssignationId]
FROM [Task] AS [T]
INNER JOIN #TaskIdTableType AS [TT] ON [T].[TaskId] = [TT].[Id]
WHERE [TaskAssignationId] is not null
))
Exists works like "Did the (sub)query return more than zero (correlated) rows" not "did the (sub)query return a non null value"
These are perfectly valid exists:
SELECT * FROM person p
WHERE EXISTS (SELECT null FROM address a WHERE a.personid = p.id)
SELECT * FROM person p
WHERE EXISTS (SELECT 1 FROM address a WHERE a.personid = p.id)
SELECT * FROM person p
WHERE EXISTS (SELECT * FROM address a WHERE a.personid = p.id)
It doesn't matter what values you return, or how many columns, exists cares whether the rowcount is 0 or greater when determining whether results exist
Hence you have to make sure your (sub)query returns no rows if you want the exists check to fail. If Addresses that have a null type are unacceptable, the (sub)query has to exclude them with WHERE a.type IS NOT NULL so that only rows with a non null type are considered
There's also little point doing a TOP 1 in the (sub)query; the optimiser knows that the only condition it cares about is 0 or not-0 rows, so it automatically do a TOP 1 (i.e. it will stop retrieving data when it knows there is at least one row)
If you want to check the existence then no need to assign the column name, you can use select 1
IF(EXISTS
SELECT TOP 1 1
FROM [Task] AS [T]
INNER JOIN #TaskIdTableType AS [TT] ON [T].[TaskId] = [TT].[Id]
))
begin
----code---
end

How to write a query to get data count with combination of codision

I have two tables named [DrugPrescriptionEdition] and [PrescriptionDoseDetail] and now, I join that two tables using the below query and taking a result set.
select * from DrugPrescription dp where id in(
SELECT distinct dpe.template
FROM [DrugPrescriptionEdition] dpe
join PrescriptionDoseDetail pdd on pdd.prescription = dpe.id
where doseEnd_endDate is NULL and doseEnd_doseEndType =1
)
but now I want to take records only contain, (1,2) combination of 'datasource' column and prescription.id should be same.
Example : like records { prescriptionID =4 and there contain ,(1,2) }. I will not consider, only 1 ,or 2 contain records.
Need some expert help to adding this conditions to my above query and modify it .
Expected result : I need to filter out , above query result using this, new condition too.
Let me assume your records are in a single table. Here is one method:
select t.*
from t
where (t.dataSource = 1 and
exists (select 1
from t t2
where t2. prescriptionid = t.prescriptionid and
t2.dataSource = 2
)
) or
(t.dataSource = 2 and
exists (select 1
from t t2
where t2.prescriptionid = t.prescriptionid and
t2.dataSource = 2
)
);
It is unclear if any other data sources are allowed. If they are not, then add:
and
not exists (select 1
from t t3
where t3.prescriptionid = t.prescriptionid and
t3.dataSource not in (1, 2)
)

Performance Issue in Left outer join Sql server

In my project I need find difference task based on old and new revision in the same table.
id | task | latest_Rev
1 A N
1 B N
2 C Y
2 A Y
2 B Y
Expected Result:
id | task | latest_Rev
2 C Y
So I tried following query
Select new.*
from Rev_tmp nw with (nolock)
left outer
join rev_tmp old with (nolock)
on nw.id -1 = old.id
and nw.task = old.task
and nw.latest_rev = 'y'
where old.task is null
when my table have more than 20k records this query takes more time?
How to reduce the time?
In my company don't allow to use subquery
Use LAG function to remove the self join
SELECT *
FROM (SELECT *,
CASE WHEN latest_Rev = 'y' THEN Lag(latest_Rev) OVER(partition BY task ORDER BY id) ELSE NULL END AS prev_rev
FROM Rev_tmp) a
WHERE prev_rev IS NULL
My answer assumes
You can't change the indexes
You can't use subqueries
All fields are indexed separately
If you look at the query, the only value that really reduces the resultset is latest_rev='Y'. If you were to eliminate that condition, you'd definitely get a table scan. So we want that condition to be evaluated using an index. Unfortunately a field that just values 'Y' and 'N' is likely to be ignored because it will have terrible selectivity. You might get better performance if you coax SQL Server into using it anyway. If the index on latest_rev is called idx_latest_rev then try this:
Set transaction isolated level read uncommitted
Select new.*
from Rev_tmp nw with (index(idx_latest_rev))
left outer
join rev_tmp old
on nw.id -1 = old.id
and nw.task = old.task
where old.task is null
and nw.latest_rev = 'y'
latest_Rev should be a Bit type (boolean equivalent), i better for performance (Detail here)
May be can you add index on id, task
, latest_Rev columns
You can try this query (replace left outer by not exists)
Select *
from Rev_tmp nw
where nw.latest_rev = 'y' and not exists
(
select * from rev_tmp old
where nw.id -1 = old.id and nw.task = old.task
)

SQL Server Return Null if exists

In SQL Server 2008 I am looking to create a query that will return a NULL in an aggregate if one exists, otherwise I'm looking for the maximum. This is a simplified example...
I have the following data:
CO Loc Term_Dt
1 A 7/15/2013
1 B
1 C 10/30/2000
2 A 8/10/2008
2 B 6/1/2015
2 C 4/30/2010
The result I'm looking for is:
CO Term_Dt
1 NULL
2 6/1/2015
because technically the Company is still open if at least one location has not yet been terminated.
Thanks
Just use aggregation and a case statement:
select co,
(case when count(term_dt) = count(*) then max(term_dt)
end) as term_dt
from table t
group by co;
count(<column>) counts the number of non-NULL values. If this doesn't match all the rows, then at least one is NULL. No else is needed for the case, because the default is NULL.
Generate a sub set of data with companies having null term dates and left join your super set to it. Any records in 2nd table which are not null you want to display as null so use a case statement.
This works because our outer table (A) returns
CO TERM_DT
1 7/15/2013
2 6/1/2015
But then our LEFT join on our inline view also adds B.Co...
CO TERM_DT B.CO
1 7/15/2013 1
2 6/1/2015 NULL
So you can see by saying we want to display NULL when B.CO is not null instead of the max(TERM_DT) will yield the desired results. This is accomplished using a case statement.
SELECT A.Co,
Case when B.CO is not null then Max(A.Term_DT) else NULL end as Term_DT
FROM tableName A
LEFT JOIN (SELECT Distinct CO from tableName where Term_dt is null) B
on A.Co = B.CO
GROUP BY CO