SQL Update trigger comparing NULL with value - sql

I'm trying to create an Update trigger on a table. The aim is to keep an audit trail of changes made to that table.
The code is long, so I'll try to simplify it here:
When the update on tbl1 happens:
#NewFirstName = FirstName
#NewLastName = LastName
From inserted
#OldFistName = FirstName
#OldLastName = LastName
From Deleted
Now I want to create a string that will tell the user something like this:
ID1 has changed from John to Michael
Here is the code I have
if (#OldFistName <> #NewFirstName )
set #AuditString = #AuditString + ' NewFirstName from ' + cast(#OldFistName as varchar) + ' to ' + cast (#NewFirstName as varchar) + ','
The problem I'm facing is that many field in the database have NULLS. So if for example, FistName is NULL, the code will not work because it is comparing NULL with something, which give me null.
Is there any way around this?
I'm using SQL Server 2008

Yes, there is a simple workaround. Just check in your if condition whether the variables are null. The code would look like:
if #OOldFistName is null
-- Your code to handle this
else if #NewFirstName is null
-- Your code to handle this
else if (#OldFistName <> #NewFirstName )
set #AuditString = #AuditString + ' NewFirstName from '
+ cast(#OldFistName as varchar) + ' to '
+ cast (#NewFirstName as varchar) + ','

Just worked out how to do this, add AND condition
if (#OldFistName is null AND #NewFirstName IS NOT NULL )
set #AuditString = #AuditString + ' FistName from ' + 'NULL ' + ' to ' + cast (#NewFirstName as varchar) + ','
ELSE
if (#OldFistName <> #NewFirstName )
set #AuditString = #AuditString + ' NewFirstName from ' + cast(#OldFistName as varchar) + ' to ' + cast (#NewFirstName as varchar) + ','

Related

Migrating 'STUFF - For XML Path' into Azure Synapse String_Agg

Been looking at this from different dngles and read multiple post but still cant get this right. Can someone provide some guidance/help? Please, Thank you!
Trying to run this in Synapse and getting errors due to the incompatible FOR XML PATH near the end.
This is a code that handles table metadata for imports. The last column will stuff the number of columns into a single line so the it can be used in a code run in sql.
SELECT source_system_table_metadata.*,
CASE
WHEN full_load = 'Y' THEN 'Truncate Table ' + target_schema + '.'
+ target_table
ELSE 'Delete from ' + target_schema + '.'
+ target_table + ' Where '
+ target_filter_column_name + ' > '''
+ source_filter_column_value + ''''
END AS Target_Table_Pre_SQL,
CASE
WHEN full_load = 'Y' THEN 'Where 1=1'
ELSE 'Where ' + source_filter_column_name + '>' + ''''
+ source_filter_column_value + ''''
END Source_Table_Filter,
CASE
WHEN col_list IS NULL THEN '*'
ELSE replace(col_list,'"','')
END col_list
FROM [gp].[source_system_table_metadata]
CROSS apply
(SELECT Stuff(
(SELECT
','
+ CONVERT(VARCHAR(200), source_column +
' as '
+
source_column_alias)
FROM [gp].[source_system_column_metadata]
WHERE
source_system_table_metadata.metadata_table_id =
source_system_column_metadata.metadata_table_id
FOR xml path(''), type
).value('.', 'VARCHAR(MAX)' ), 1, 1, ''
) AS col_list
)table_columns
Where isnull(active_status,'N') = 'Y'
Have the code run and concatenate the Stuff in the last piece correctly in Synapse

I'm having an issue with syntax in a Stored SQL Procedure

I'm trying to add three additional columns to a stored procedure (I don't have a lot of experience in stored procedures), the columns are Family ID, Address, and Phone No. Although I've run the query and confirmed the syntax for my select statement is correct, when I add the statement to the stored proc, I receive the following error: Incorrect syntax near 'capPrograms'(this would be line 14). I know this probably has to do with hoe I'm trying to implement my statement in the procedure to update it, but I'm not quite sure what the issues as I've tried several changes with similar or more extensive errors. Any assistance is appreciated, I've included the block of code I'm working with below:
SELECT capCase.Id AS capCase_Id,
capCase.DateApplied AS capCase_DateApplied,
CASE
WHEN ISNUMERIC(#cases.origCaseYear)=1 THEN CAST(origCaseYear + 2004 AS VARCHAR) + ' - ' + CAST(capCase.IdYear + 2004 AS VARCHAR)
WHEN #cases.maxRolloverYear IS NOT NULL THEN CAST(capCase.IdYear + 2004 AS VARCHAR) + ' - ' + CAST(#cases.MaxRolloverYear + 2004 AS VARCHAR)
ELSE CAST(capCase.IdYear + 2004 AS VARCHAR)
END AS capCase_IdYear,
Person.id as Person_id,
Person.LastName + ', ' + Person.FirstName AS PersonPrint_Name,
person.idFamily AS Family_ID, person.homePhone AS Phone_No, (SELECT family.physicalAddress1+ ', ' + family. physicalAddressCity+ ' ' +family. physicalAddressZip) AS Address
FROM Family
LEFT JOIN person ON family.Id = person.idFamily;
capPrograms.Program AS capPrograms_Program,
capStatus.Status AS capStatus_Status,
#lastFollowup.followupDate AS capCaseFollowup_Date,
CASE
WHEN capCase.IdCaseWorker IS NULL THEN 'No Worker Assigned'
ELSE caseWorker.LastName + ', ' + caseWorker.FirstName + ISNULL('<' + caseWorker.EmailWork + '>', '')
END AS capCase_IdCaseWorker,
capcaseDenialReason.reason AS capCase_idDenialReason,
Too long to comment, so I added a bunch of comments in your code. You have, A LOT of issues.
SELECT
capCase.Id AS capCase_Id,
capCase.DateApplied AS capCase_DateApplied,
CASE
--here you are referencing a temp table, which isn't joined below
WHEN ISNUMERIC(#cases.origCaseYear)=1 THEN CAST(origCaseYear + 2004 AS VARCHAR) + ' - ' + CAST(capCase.IdYear + 2004 AS VARCHAR)
WHEN #cases.maxRolloverYear IS NOT NULL THEN CAST(capCase.IdYear + 2004 AS VARCHAR) + ' - ' + CAST(#cases.MaxRolloverYear + 2004 AS VARCHAR)
ELSE CAST(capCase.IdYear + 2004 AS VARCHAR)
END AS capCase_IdYear,
Person.id as Person_id,
Person.LastName + ', ' + Person.FirstName AS PersonPrint_Name,
person.idFamily AS Family_ID,
person.homePhone AS Phone_No,
--this subquery as no from clause... that's an issue... you probably want to remove it completly and replace it with the one below
(SELECT family.physicalAddress1+ ', ' + family. physicalAddressCity+ ' ' +family. physicalAddressZip) AS Address,
--this is likely what you want
family.physicalAddress1 + ', ' + family. physicalAddressCity + ' ' + family. physicalAddressZip AS AddressCorrected
FROM Family
LEFT JOIN person ON
family.Id = person.idFamily; --you have a ; here, which terminates the statement. Everything else below isn't included
--Here you need to join the capPrograms and #lastFollowup table..
--here, you listed some columns, without a table reference. You need to join the table above, and move these columns above the FROM clause
capPrograms.Program AS capPrograms_Program,
capStatus.Status AS capStatus_Status,
#lastFollowup.followupDate AS capCaseFollowup_Date,
CASE
WHEN capCase.IdCaseWorker IS NULL THEN 'No Worker Assigned'
ELSE caseWorker.LastName + ', ' + caseWorker.FirstName + ISNULL('<' + caseWorker.EmailWork + '>', '')
END AS capCase_IdCaseWorker,
capcaseDenialReason.reason AS capCase_idDenialReason,

How to optimize MSSQL CASE WHEN queries

Here's a sample of my code:
SET #variable_out =
'Report: '
+ CASE WHEN (SELECT name FROM person WITH(NOLOCK) WHERE person_id = #person_id) != ''
THEN 'Name: ' + (SELECT name FROM person WITH(NOLOCK) WHERE person_id = #person_id) + CHAR(13)+CHAR(10)
ELSE 'Name: not found' + CHAR(13)+CHAR(10)
END
+ CASE WHEN (SELECT home_phone FROM person WITH(NOLOCK) WHERE person_id = #person_id) != ''
THEN 'Phone #: ' + (SELECT home_phone FROM person WITH(NOLOCK) WHERE person_id = #person_id) + CHAR(13)+CHAR(10)
ELSE 'Phone #: not found' + CHAR(13)+CHAR(10)
END
etc...
As you can see, I am redundantly performing two selects for each CASE WHENE... of the variable that I am constructing, and I would love to collapse this down to only one select for each line.
The only solution I know of would be to create a unique variable for CASE WHEN..., run all of the selects before hand, and then if the variables aren't empty, concat them into #variable_out.
Is there a more clever way to accomplish this?
DECLARE #name the_same_datatype_as_name_field_from_person_table --Ex. VARCHAR(100)
,#home_phone the_same_datatype_as_homephone_field_from_person_table; --Ex. VARCHAR(15)
SELECT #name = NULLIF(p.name,''), #home_phone = NULLIF(p.home_phone,'')
FROM person p --WITH(NOLOCK)
WHERE p.person_id = #person_id;
SET #variable_out =
'Report: '
+ ISNULL('Name: ' + #name, 'Name: not found')
+ CHAR(13)+CHAR(10)
+ ISNULL('Phone #: ' + #home_phone, 'Phone #: not found')
+ CHAR(13)+CHAR(10);
Note:
or, you can use for #name & #home_phone variables the same data type like as #variable_out variable (ex. VARCHAR).
NOLOCK pros & cons.

Combine First, Middle Initial, Last name and Suffix in T-SQL (No extra spaces)

I'm trying not to reinvent the wheel here...I have these four fields:
[tbl_Contacts].[FirstName],
[tbl_Contacts].[MiddleInitial],
[tbl_Contacts].[LastName],
[tbl_Contacts].[Suffix]
And I want to create a FullName field in a view, but I can't have extra spaces if fields are blank...
So I can't do FirstName + ' ' + MiddleInitial + ' ' + LastName + ' ' + Suffix... Because if there is no middle initial or suffix I'd have 2 extra spaces in the field. I think I need a Case statement, but I thought someone would have a handy method for this...Also, the middleinitial and suffix may be null.
Assuming that all columns could be nullable, you can do something like:
RTrim(Coalesce(FirstName + ' ','')
+ Coalesce(MiddleInitial + ' ', '')
+ Coalesce(LastName + ' ', '')
+ Coalesce(Suffix, ''))
This relies on the fact that adding to a NULL value yields a NULL.
Whichever options you choose, here's something to think about: this will be a rather involved and thus time consuming option, especially if you have it in a view which gets evaluated each and every time for each and every row in question.
If you need this frequently, I would recommend you add this to your base table as a persisted, computed field - something like:
ALTER TABLE dbo.tbl_Contacts
ADD FullName AS (insert the statement of your choice here) PERSISTED
When it's persisted, it becomes part of the underlying table, and it's stored and kept up to date by SQL Server. When you query it, you get back the current value without incurring the cost of having to concatenate together the fields and determine which to use and which to ignore...
Just something to think about - something that too many DBA's and database devs tend to ignore and/or not know about....
You may want to pass the FirstName + ' ' + MiddleInitial + ' ' + LastName + ' ' + Suffix concatenation through the REPLACE() function in order to substitute duplicate spaces into a single space.
REPLACE(FirstName + ' ' + MiddleInitial + ' ' + LastName + ' ' + Suffix, ' ', ' ')
-- -- -
EDIT:
Just noticed that some of your fields may be NULL, and therefore the above would not work in that case, as the whole string would become NULL. In this case, you can use the COALESCE() method as suggested by Thomas, but still wrapped it in a REPLACE():
REPLACE(RTRIM(COALESCE(FirstName + ' ', '') +
COALESCE(MiddleInitial + ' ', '') +
COALESCE(LastName + ' ', '') +
COALESCE(Suffix, '')), ' ', ' ')
Test:
SELECT REPLACE(RTRIM(COALESCE('John' + ' ', '') +
COALESCE('' + ' ', '') +
COALESCE('Doe' + ' ', '') +
COALESCE(NULL, '')), ' ', ' ')
-- Returns: John Doe
I had to join Firstname, Middlename, and Lastname. my challenge was to handle NULL values, used following code.
RTRIM(LTRIM(RTRIM(isnull(#firstname,'') + ' ' + isnull(#middlename,'')) + ' ' + isnull(#lastname,'')))
Test different scenarios if you are interested :)
DECLARE #firstname VARCHAR(MAX)
DECLARE #middlename VARCHAR(MAX)
DECLARE #lastname VARCHAR(MAX)
set #firstname = 'FirstName'
set #middlename = NULL
set #lastname = 'LastName'
SELECT '|'+RTRIM(LTRIM(RTRIM(isnull(#firstname,'') + ' ' + isnull(#middlename,'')) + ' ' + isnull(#lastname,'')))+'|'
--
If you are using SQL Server 2012+ you could use CONCAT and +:
SELECT RTRIM(
CONCAT(FirstName + ' ', MiddleInitial + ' ', LastName + ' ', Suffix)
) AS [FullName]
FROM tbl_Contacts;
How it works:
If any part of full name is NULL then NULL + ' ' → NULL
CONCAT handles NULL
In case that after part of name there are only NULLs, TRIM last space.
LiveDemo
Here is a solution:
CREATE FUNCTION dbo.udf_IsNullOrEmpty
(
#vchCheckValue VARCHAR(MAX)
,#vchTrueValue VARCHAR(MAX)
,#vchFalseValue VARCHAR(MAX)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
RETURN CASE WHEN NULLIF(RTRIM(LTRIM(#vchCheckValue)),'') IS NULL THEN #vchTrueValue ELSE #vchFalseValue END
END
SELECT FirstName + ' ' +
dbo.udf_IsNullOrEmpty(MiddleInitial,'',MiddleInitial + ' ') +
LastName +
dbo.udf_IsNullOrEmpty(Suffix,'',' ' + Suffix)
FROM tbl_Contacts
select CONCAT(IFNULL(FirstName, ''),
'',
IFNULL(MiddleName, ''),
'',
IFNULL(LastName, '')) AS name
from table
Why not like this:
select concat(fName,' ',
case length(mName)
when 0 then ''
else concat(mName, ' ') end, lName) as fullName
My columns are not null, so this works for me.
create function getfname(#n varchar(30))
returns varchar(30)
as
begin
declare #s varchar(30)
set #s=LEFT(#n,charindex(' ',#n)-1)
return #s
end
create function getLname(#n varchar(30))
returns varchar(30)
as
begin
declare #s varchar(30)
set #s=substring(#n,charindex(' ',#n+1),Len(#n))
return #s
end
the query:
SELECT retire.employeehrmsid,
Isnull(retire.firstname, '') + ' '
+ Isnull(retire.middlename, '') + ' '
+ Isnull(retire.lastname, '') AS FullName,
retire.dojtoservice,
retire.designation,
emphistory.currentdoj,
emphistory.presentddo,
emphistory.office,
transfer.generatetid AS TransferID,
transfer.transferdate,
transfer.currentlocation,
transfer.newlocation,
transfer.datas AS Transfer_Doc,
release.generaterid AS ReleaseID,
release.releasedate,
release.datar AS Release_Doc,
employeeserviceupdate.dataeu AS Join_Doc
FROM retire
INNER JOIN emphistory
ON retire.id = emphistory.id
INNER JOIN employeeserviceupdate
ON retire.id = employeeserviceupdate.id
INNER JOIN transfer
ON retire.id = transfer.id
AND emphistory.ehrid = transfer.ehrid
INNER JOIN release
ON transfer.tid = release.tid

What's the shortest TSQL to concatenate a person's name which may contain nulls

3 fields: FirstName, MiddleName, LastName
Any field can be null, but I don't want extra spaces. Format should be "First Middle Last", "First Last", "Last", etc.
LTRIM(RTRIM(
LTRIM(RTRIM(ISNULL(FirstName, ''))) + ' ' +
LTRIM(RTRIM(ISNULL(MiddleName, ''))) + ' ' +
LTRIM(ISNULL(LastName, ''))
))
NOTE: This won't leave trailing or leading spaces. That's why it's a little bit uglier than other solutions.
Assuming by "extra spaces", you mean extra spaces inserted during the concatenation (which is a reasonable assumption, I think. If you have extra spaces in your data, you should clean it up):
ISNULL(FirstName + ' ', '') + ISNULL(MiddleName + ' ', '') + ISNULL(LastName, '')
works, since you'll add a space to the name - which if it's NULL yields NULL - which yields empty string.
Edit: If you don't count the SET OPTION - which can be a connection or db option:
SET CONCAT_NULL_YIELDS_NULL OFF
LTRIM(FirstName + ' ' + NULLIF(MiddleName + ' ', ' ') + LastName)
is a tiny bit shorter, but a large bit uglier.
Edit2: Since you accepted the UDF answer - IMO, that's a bit of a cheat - here's some in the same vein:
SELECT a FROM b
b is a view. ;) Or. a stored proc,
EXEC c
But, since EXEC is optional:
c
use a UDF:
`Select udfConcatName(First, Middle, Last) from foo`
That way all your logic for concatenating names is in one place and once you've gotten it written it's short to call.
LTRIM(RTRIM(ISNULL(FirstName, '') + ' ' + LTRIM(ISNULL(MiddleName, '') + ' ' +
ISNULL(LastName, ''))))
Why not use a computed column on the table that performs the concat for you using your preferred syntax from the many posted here? Then you will just query the computed column - very elegant and if you persist the computed column then you may even get slight performance increase.
Example here
replace(ltrim(rtrim(isnull(FirstName, '') + ' ' + isnull(MiddleName, '') + ' ' + isnull(LastName, ''))), ' ', ' ')
'"' + ltrim(rtrim(isnull(FirstName,''))) + ' ' + ltrim(rtrim(isnull(MiddleName,''))) +
' ' + ltrim(rtrim(isnull(LastName,''))) + '","' + ltrim(rtrim(isnull(FirstName,''))) +
' ' + ltrim(rtrim(isnull(LastName,''))) + '","' + ltrim(rtrim(isnull(LastName,''))) +
'"'
ETC
DECLARE #first varchar(10) = 'First'
DECLARE #middle varchar(10) = ''
DECLARE #last varchar(10) = 'Last'
LTRIM(RTRIM(
#first
+ ISNULL(NULLIF(' '+LTRIM(RTRIM(#middle)),' '),'')
+ ISNULL(NULLIF(' '+LTRIM(RTRIM(#last)),' '),'')
))
WHY THIS WORKS
The fields are reduced to an empty string if NULL or whitespace by the LTRIM, RTRIM, and ISNULL functions.
LTRIM(RTRIM(ISNULL(#middle,''))) -- Result is a trimmed non-null string value.
That value is prefixed with a single space, then compared to a single space by the NULLIF function. If equal, a NULL results. If not equal, then the value is used.
NULLIF(' '+'',' ') -- this would return NULL
NULLIF(' '+'Smith',' ') -- this would return ' Smith'
Finally, ISNULL() is used to convert the NULL passed by NULLIF to an empty string.
ISNULL(NULL,'') -- this would return ''
ISNULL(' Smith','') -- this would return ' Smith'
LTrim(RTrim(Replace(IsNull(Firstname + ' ', '') +
isNull(MiddleName, '') +
IsNull(' ' + LastName, ''), ' ', ' ')))
Select firstname, middlename, lastname, ProvidedName =
RTrim(Coalesce(FirstName + ' ','')
+ Coalesce(MiddleName + ' ', '')
+ Coalesce(LastName + ' ', '')
+ COALESCE('' + ' ', '')
+ COALESCE(NULL, ''))
From names