Insert data if it does not exist - sql

I want to insert some data in my column only if my query parameters are not already added.
For example, if my row contains :
a=4&b=7&c=9
and now, when update happens with : b=7&c=9, then i should not append it.
o/p:a=4&b=7&c=9
But if update happens with d=9&e=9
then it should append it.
o/p : a=4&b=7&c=9&d=9&e=9
My normal Update query is :
#AdditionalParams = 'b=7&c=9'
SELECT #id = mid FROM Table2 WHERE sid = #SId
AND cid = #CId;
UPDATE Table1
SET additional_params = CONCAT (
additional_params
,iif(additional_params IS NULL, NULL, '&')
,#AdditionalParams
)
WHERE mid = #id
How can i use here the NOT EXIST Clasue.
But with not exist clause it checks whole row, I just want to check if parameters exist, then dont insert it.

I guess you are looking for a not like clause
declare #AdditionalParams varchar(50) = 'b=7&c=8'
SELECT #id = mid
FROM Table2
WHERE sid = #SId
AND cid = #CId;
UPDATE Table1
SET additional_params = CONCAT (
additional_params
,iif(additional_params IS NULL, NULL, '&')
,#AdditionalParams
)
WHERE mid = #id
and additional_params not like '%'+ #AdditionalParams +'%';

Related

Using multiple nested OR statements in WHERE clause makes query return incorrect results

I have a WHERE clause that has a nested OR statement, as seen here:
-- Declaration of variables
DECLARE
#PageSize INT,
#PageNumber INT,
#SearchPhraseOne VARCHAR(20),
#SearchPhraseTwo VARCHAR(20),
#FilterCategory VARCHAR(30),
#FilterStatus TINYINT,
#NeedsFollowUp TINYINT,
#NeedsTraining TINYINT,
#NeedsInitialVacc TINYINT;
SET #PageNumber = 1;
SET #PageSize = 100;
SET #SearchPhraseOne = null;
SET #SearchPhraseTwo = null;
SET #FilterCategory = 'High Exposure';
SET #FilterStatus = null;
SET #NeedsFollowUp = 1;
SET #NeedsTraining = null;
SET #NeedsInitialVacc = null;
select * from(
select
vel.fullName,
vel.EecEmpNo,
vel.EecLocation,
vel.EecDateOfLastHire,
job.JbcDesc,
vei.eiInitialBBPDate,
vei.eiVCGivenDate,
iif(jv.verTypeName is null, 'Low Risk', jv.verTypeName) as vaccineCategory,
vel.eecEmplStatus,
count(distinct vh.vhID) as vaccCount,
max(isnull(vh.vhNextDateScheduled, null)) as maxNextDateScheduled,
max(cast(vh.vhSeriesComplete as int)) as seriesComplete,
iif(vel.eecEmplStatus = 'T', null,
coalesce(iif(max(cast(vh.vhSeriesComplete as int)) = 1, null, max(isnull(vh.vhNextDateScheduled, null))), -- check if the vaccine items have a SeriesComplete of 1, otherwise use NextDateScheduled
iif(vei.eiInitialBBPDate is not null, null, vel.EecDateOfLastHire), -- check if the InitialBBPDate is not null, if it isn't use DateOfLastHire
iif(vei.eiVCGivenDate is not null, null, vel.EecDateOfLastHire), null)) as actionDate -- check if the OrientationDate is not null, if it isn't use DateOfLastHire
-- if all three of these values are null then there's no ActionDate
-- Terminated employees will not have an action date assigned even if there's a match
from dbo.vaccEmpList vel
left join dbo.vaccEmployeeInfo vei on vei.eiEmployeeNo = vel.EecEmpNo
left join dbo.vaccVaccinationHistory vh on vh.vhEmployeeNo = vel.EecEmpNo
left join dbo.vaccVaccineTypeLookup vt on vh.vhVaccinationTypeID = vt.vtlVaccineTypeID and vt.vtIsActive = 1 -- Only get active vaccination types
join dbo.U_JobCode job on vel.EecJobCode = job.JbcJobCode
left join dbo.JobVerficationXref jv on vel.EecJobCode = jv.JobCode and jv.verName = 'Vaccination Category'
group by vel.fullName, vel.EecEmpNo, job.JbcDesc, jv.verTypeName, vel.EecLocation, vel.eecEmplStatus, vei.eiInitialBBPDate, vei.eiVCGivenDate, vel.EecDateOfLastHire
) as searchResults
where (
(
#SearchPhraseOne is null
or searchResults.fullName like #SearchPhraseOne + '%'
or searchResults.EecEmpNo = #SearchPhraseOne
)
and (
#SearchPhraseTwo is null
or searchResults.fullName like #SearchPhraseTwo + '%'
or searchResults.EecEmpNo = #SearchPhraseTwo
) -- Employee Name/ID
and (
#FilterStatus is null
or (searchResults.eecEmplStatus = 'A' or searchResults.eecEmplStatus = 'L')
) -- Employee Status
and (
#FilterCategory is null
or searchResults.vaccineCategory = #FilterCategory
) -- Employee Vaccination Category
and ( -- ISSUES OCCUR HERE
(#NeedsTraining is null
or (searchResults.actionDate is not null
and (searchResults.eiInitialBBPDate is null or searchResults.eiVCGivenDate is null))
) -- Needs Training if either of these two date values are null
or (#NeedsInitialVacc is null
or (searchResults.actionDate is not null
and (searchResults.vaccCount = 0))
-- Needs Initial Vaccination if there are no vaccine records
)
or (#NeedsFollowUp is null
or (searchResults.actionDate is not null
and ((searchResults.seriesComplete is null or searchResults.seriesComplete = 0) and searchResults.maxNextDateScheduled is not null))
-- Needs a follow-up date if no series complete was detected
)
)
)
The #NeedsFollowUp, #NeedsInitialVacc, and #NeedsTraining variables are all set by the variables above. When one or more of these are set to "1", the query should return employee entries that match the criteria inside their related statements. For example, if the "NeedsFollowUp" and "NeedsTraining" values are set to "1" then the query should return employees that need a follow-up or employees that need training.
Right now, when I set all three to "1" I receive the combined results I'm looking for, but if any of them are set to null, then the query doesn't return the correct results.
EDIT: Here's a reproducible example of what I'm seeing.
I think the way the clauses are set up is causing an issue, but I'm not really sure how to fix this. How can I get the OR statements to work in the way I described above?
I was able to make the OR clauses work correcting by switching from is null to is not null in my where clauses. Using the minimal example, it would look like this:
select * from AGENTS
where (
(#NeedsName is not null and AGENTS.AGENT_NAME is null)
or
(#NeedsCountry is not null and AGENTS.COUNTRY is null)
or
(#NeedsCountry is null and #NeedsName is null)
)
Be sure to include an additional clause for when all options are NULL, so that you can return the appropriate number of rows.
Here's a working version.

not able to use not exist keyword if subquery does not have join with query

i want to update [dbo].[ErrorLogs] if key with value 'ABCDEF' does not exist in [dbo].[BatchEncryptedKeys].
But the problem is to use 'not exists' keyword, i should have join with table [dbo].[ErrorLogs] [dbo].[BatchEncryptedKeys] on their common column.
but there is no common column between them.
can anyone suggest the alternate solution?
sample data
table ErrorLogs
[ID] [ProcessedOnDate] [ErrorMessage] [ExternalID]
1 2020-07-22 'Invalid CompanyID' 'EXT-001'
2 2020-07-22 'Invalid CompanyName' 'EXT-002'
table BatchEncryptedKeys
[ID] [CompanyID] [CompanyName] [Key]
1 34212 'Marines International' 'JABSCAIBCJS'
2 23421 'TCS' 'AJIDSBAIU'
what i want is, if key = 'ABCDEF' does not exist in [dbo].[BatchEncryptedKeys]
table then i want to update the ErrorMessage column of [dbo].[ErrorLogs] table
with message "Invalid Key".
'ABCDEF' is a Encrypted Key provided by user as a input.
input can be anything.
i am just checking if that input exists in my table or not.
if not then that key is invalid.
update [dbo].[ErrorLogs]
set
ProcessedOnDate = GETDATE(),
ErrorMessage = Concat(ErrorMessage,' Key is Invalid. ')
where ID = 36
and not exists (
select * from [dbo].[BatchEncryptedKeys]
where Key = 'ABCDEF'
);
If the problem is that the Message is not updated ... try ...
update [dbo].[ErrorLogs] set
ProcessedOnDate = GETDATE(),
ErrorMessage = ISNULL(ErrorMessage, '') + ' Key is Invalid. '
where
ID = 36
and not exists (
select * from [dbo].[BatchEncryptedKeys] where Key = 'ABCDEF'
);
Assuming this is running in a stored procedure that you're passing parameters into (and that I understand your need), try this:
DECLARE
#Key VARCHAR(50) = 'ABCDEF',
#Id INT = 36;
IF NOT EXISTS ( SELECT * FROM [dbo].[BatchEncryptedKeys] WHERE [Key] = #Key )
BEGIN
UPDATE [dbo].[ErrorLogs]
SET
ProcessedOnDate = GETDATE(),
ErrorMessage = CONCAT ( ISNULL ( ErrorMessage, '' ), ' Key is Invalid. ' )
WHERE ID = #Id;
END

IF ELSE condition in SQL select

I want to do a if-else condition statement in SQL Server but am not sure how.
Inside the stored procedure I have the following parameters:
#MarketId nvarchar (10),
#RegionId nvarchar (10)
And the following statement:
select * from Interaction I
where
(#MarketId = 0 ) OR (I.MarketId = (SELECT Id FROM Market WHERE ExternalId = #MarketId))
What I want to do is to check the value of #MarketId
if #MarketId = 0
then I want the where condition for I.MarketId to get its Ids from elsewhere like
(SELECT ID FROM Market WHERE ExternalId = #RegionId)
otherwise, if its 1, then I just want to leave it as is and get the Id from #MarketId instead of #RegionId..
How should I go about this?
Thanks!
This should work:
SELECT *
FROM Interaction I
WHERE ( #MarketID = 0
AND EXISTS (SELECT 1 FROM Market
WHERE ExternalId = #RegionId AND Id = I.MarketID)
OR I.MarketID = #MarketID

SQL WHERE ... IN clause with possibly null parameter

I am having some problems with my WHERE clause (using SQL 2008) . I have to create a stored procedure that returns a list of results based on 7 parameters, some of which may be null. The ones which are problematic are #elements, #categories and #edu_id. They can be a list of ids, or they can be null. You can see in my where clause that my particular code works if the parameters are not null. I'm not sure how to code the sql if they are null. The fields are INT in the database.
I hope my question is clear enough. Here is my query below.
BEGIN
DECLARE #elements nvarchar(30)
DECLARE #jobtype_id INT
DECLARE #edu_id nvarchar(30)
DECLARE #categories nvarchar(30)
DECLARE #full_part bit
DECLARE #in_demand bit
DECLARE #lang char(2)
SET #jobtype_id = null
SET #lang = 'en'
SET #full_part = null -- full = 1, part = 0
SET #elements = '1,2,3'
SET #categories = '1,2,3'
SET #edu_id = '3,4,5'
select
jobs.name_en,
parttime.fulltime_only,
jc.cat_id category,
je.element_id elem,
jt.name_en jobtype,
jobs.edu_id minEdu,
education.name_en edu
from jobs
left join job_categories jc
on (jobs.job_id = jc.job_id)
left join job_elements je
on (jobs.job_id = je.job_id)
left join job_type jt
on (jobs.jobtype_id = jt.jobtype_id)
left join education
on (jobs.edu_id = education.edu_id)
left join
(select job_id, case when (jobs.parttime_en IS NULL OR jobs.parttime_en = '') then 1 else 0 end fulltime_only from jobs) as parttime
on jobs.job_id = parttime.job_id
where [disabled] = 0
and jobs.jobtype_id = isnull(#jobtype_id,jobs.jobtype_id)
and fulltime_only = isnull(#full_part,fulltime_only)
-- each of the following clauses should be validated to see if the parameter is null
-- if it is, the clause should not be used, or the SELECT * FROM ListToInt... should be replaced by
-- the field evaluated: ie if #elements is null, je.element_id in (je.element_id)
and je.element_id IN (SELECT * FROM ListToInt(#elements,','))
and jc.cat_id IN (SELECT * FROM ListToInt(#categories,','))
and education.edu_id IN (SELECT * FROM ListToInt(#edu_id,','))
order by case when #lang='fr' then jobs.name_fr else jobs.name_en end;
END
Something like
and (#elements IS NULL OR je.element_id IN
(SELECT * FROM ListToInt(#elements,',')))
and (#categories IS NULL OR
jc.cat_id IN (SELECT * FROM ListToInt(#categories,',')))
....
should do the trick
je.element_id IN (SELECT * FROM ListToInt(#elements,',')) OR #elements IS NULL
that way for each one
Have you tried explicitly comparing to NULL?
and (#elements is null or je.element_id IN (SELECT * FROM ListToInt(#elements,','))
And so on.

More efficient double coalesce join alternative

I have a procedure with a (slightly more complex) version of the below:
CREATE PROC sp_Find_ID (
#Match1 varchar(10),
#Match2 varchar(10)
) AS
DECLARE #ID int
SELECT #ID = ID
FROM Table1
WHERE Match1 = #Match1
AND Coalesce(Match2,#Match2,'') = Coalesce(#Match2,Match2,'')
SELECT #ID ID
Essentially Match1 is a mandatory match, but Match2 is both optional on the input to the procedure, and on the table being searched. The 2nd match succeeds where the input and/or the table Match2 values are null, or where they're both the same (not null) value.
My question is: Is there a more efficient (or even more readable) way of doing this?
I've used this method a few times, and I feel slightly sullied each time (subjective dirtiness admittedly).
Is there a more efficient (or even more readable) way of doing this?
The example you provided, using COALESCE/etc is non-sargable. You need to separate things so only what needs to be present in the query is run:
DECLARE #ID int
IF #Match2 IS NOT NULL
BEGIN
SELECT #ID = t.id
FROM TABLE1 t
WHERE t.match1 = #Match1
AND (t.match2 = #Match2 OR t.match2 IS NULL)
END
ELSE
BEGIN
SELECT #ID = t.id
FROM TABLE1 t
WHERE t.match1 = #Match1
END
SELECT #ID ID
If you want this to occur in a single SQL statement, dynamic SQL is the only real alternative. I highly recommend reading The curse and blessing of dynamic SQL before reading further:
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = N' SELECT #ID = t.id
FROM TABLE1 t
WHERE t.match1 = #Match1 '
SET #SQL = #SQL + CASE
WHEN #Match2 IS NOT NULL THEN
' AND (t.match2 = #Match2 OR t.match2 IS NULL) '
ELSE
' '
END
BEGIN
EXEC sp_executesql #SQL,
N'#ID INT OUTPUT, #Match1 VARCHAR(10), #Match2 VARCHAR(10)',
#ID, #Match1, #Match2
END
Avoiding OR and ISNULL etc
The EXCEPT bit returns no rows if either side IS NULL
Match2 <> #Match2 means exclude non-NULL non-matching
Something like this
DROP TABLE dbo.Table1
CREATE TABLE dbo.Table1 (ID int NOT NULL, Match1 int NOT NULL, Match2 int NULL)
INSERT dbo.Table1 VALUES (1, 55, 99), (2, 55, NULL)
DECLARE #Match1 int = 55, #Match2 int
SELECT ID
FROM
(
SELECT ID FROM Table1 WHERE Match1 = #Match1
EXCEPT -- #Match2 = NULL, match both rows (99, NULL)
SELECT ID FROM Table1 WHERE Match2 <> #Match2
) foo
SET #Match2 = -1
SELECT ID
FROM
(
SELECT ID FROM Table1 WHERE Match1 = #Match1
EXCEPT -- #Match2 = -1, match ID = 2 only where Match2 IS NULL
SELECT ID FROM Table1 WHERE Match2 <> #Match2
) foo
Don't know if this is any more preferable.
SELECT #ID = ID
FROM Table1
WHERE Match1 = #Match1
AND ((Match2 = #Match2) OR Coalesce(Match2,#Match2) IS NULL)
I would have thought this should do it - providing that the #Match2 value will be NULL if it is optional.
CREATE PROC sp_Find_ID (
#Match1 varchar(10),
#Match2 varchar(10)
) AS
DECLARE #ID int
SELECT #ID = ID
FROM Table1
WHERE Match1 = #Match1
AND Match2 = IsNull(#Match2, Match2)
SELECT #ID ID
Seems simple to me? I must be missing something.. you dont need the Coalesce
SELECT #ID = ID
FROM Table1
WHERE Match1 = #Match1
AND (
(Match2 is null and #Match2 is null)
or
#Match2=Match2
)
SELECT #ID ID