Say I've got a function or stored procedure that takes in several VARCHAR parameters. I've gotten tired of writing SQL like this to test if these parameters have a value:
IF #SomeVarcharParm IS NOT NULL AND LEN(#SomeVarcharParm) > 0
BEGIN
-- do stuff
END
There's gotta be a better way to do this. Isn't there?
You can do ISNULL(#SomeVarcharParam, '') <> '' or you can create a UDF that returns a bit:
create function dbo.IsNullOrEmpty(#x varchar(max)) returns bit as
BEGIN
IF #SomeVarcharParm IS NOT NULL AND LEN(#SomeVarcharParm) > 0
RETURN 0
ELSE
RETURN 1
END
And call that using IF NOT dbo.IsNullOrEmpty(#SomeVarcharParam) BEGIN ...
Keep in mind that when calling a UDF, you MUST prefix the owner of it (here, dbo.)
IF COALESCE(#SomeVarcharParm, '') <> ''
BEGIN
-- do stuff
END
If I'm concatenating or coalescing a string inline (within a select statement), and I want to check if the column is NULL or Empty, I do this:
ISNULL('starting to build string '
+ NULLIF(some_table..some_col_that_might_be_null_or_empty, '')
, 'string to append if the resulting concatenation is null')
The NULLIF on the inner part of the expression will force the column to be NULL if it's empty, then the outer ISNULL expression can depend on consistent input and react accordingly.
Here is my function that "extends" ISNULL and checks for empty as well. The test value is checked for null and if it is not null it is trimmed and then checked for length.
The function returns the test string if it is NOT Null or Empty, otherwise the second string is returned.
CREATE FUNCTION [dbo].[ISNULLOREMPTY]
(
#value NVARCHAR(max),
#return NVARCHAR(max)
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
IF (#value IS NULL)
BEGIN
RETURN #return
END
ELSE
BEGIN
IF (LEN(LTRIM(#value)) = 0)
BEGIN
RETURN #return
END
END
RETURN #value;
END
GO
I upvoted Atron's answer though he technically implemented IfNullOrWhiteSpace.
Here's my implementation of IfNullOrEmpty():
IF EXISTS (SELECT * FROM sys .objects WHERE object_id = OBJECT_ID(N'[dbo].[IfNullOrEmpty]' ) and type in ( N'FN'))
DROP FUNCTION dbo.IfNullOrEmpty
go
CREATE FUNCTION dbo.IfNullOrEmpty(#value varchar(max), #substitute varchar(max)) returns varchar(max) as
BEGIN
IF #value IS NOT NULL AND LEN(#value) > 0
RETURN #value
RETURN #substitute
END
I realize this is an old question, but this is what I use in MSSQL:
LEN(ISNULL(#asdf, ''))>0
Example:
DECLARE #asdf varchar(10)
SET #asdf = NULL --You can change this value to test different outputs
BEGIN IF LEN(ISNULL(#asdf, '')) > 0
PRINT #asdf
ELSE
PRINT 'IS NullOrEmpty'
END
--You can use it inline like this:
PRINT CASE LEN(ISNULL(#asdf, '')) WHEN 0 THEN 'IS NullOrEmpty' ELSE #asdf END
I think this is simpler and more straight forward than the other solutions because it is literally checking if the string is null or has a length of 0.
You don't need to check for null before calling LEN. You can just use LEN(#SomeVarcharParm) > 0. This will return false if the value is NULL, '', or ' '. This is because NULL > 0 returns false. See for yourself run:
SELECT
CASE WHEN NULL > 0 THEN 'NULL > 0 = true' ELSE 'NULL > 0 = false' END,
CASE WHEN LEN(NULL) > 0 THEN 'LEN(NULL) = true' ELSE 'LEN(NULL) = false' END,
CASE WHEN LEN('') > 0 THEN 'LEN('''') > 0 = true' ELSE 'LEN('''') > 0 = false' END,
CASE WHEN LEN(' ') > 0 THEN 'LEN('' '') > 0 = true' ELSE 'LEN('' '') > 0 = false' END,
CASE WHEN LEN(' test ') > 0 THEN 'LEN('' test '') > 0 = true' ELSE 'LEN('' test '') > 0 = false' END
You can just do IF #SomeVarcharParam <> '' since the condition will evaluate to NULL and the branch won't be taken if the parameter is null
Use this function (based on Derek's):
CREATE FUNCTION dbo.isNullOrEmpty(#x varchar(max)) RETURNS BIT AS
BEGIN
IF #x IS NOT NULL AND LEN(#x) > 0
RETURN 0
RETURN 1
END
as
dbo.isNullOrEmpty(#someVar)
or
WHERE dbo.isNullOrEmpty(#someVar) = 1
in a stored procedure or query.
please use case command.case structure is:
case when condition then 'some value' else 'some other value' end
some example:
declare #SomeVarcharParm as nvarchar(20)=''
declare #SomeVarcharParm2 as nvarchar(20)=''
--select 1 or 2
select case when #SomeVarcharParm is null or #SomeVarcharParm='' then 1 else 2 end
--if null or empty set 'empty' value else set #SomeVarcharParm value
select #SomeVarcharParm2=case when #SomeVarcharParm is null or #SomeVarcharParm='' then 'empty' else #SomeVarcharParm end
--use null or empty in update command
update tbl1
set field1=case when field1 is null or field1='' then #SomeVarcharParm2 else field1 end
where id=1
Related
I have a variable like this
DECLARE #CODE NVARCHAR(10) = '09000:09502';
I need to split the #CODE variable into two variables and insert them into a temporary table for doing bulk insert.
But when I using 'CASE WHEN' inside my select statement, the value after split will remove the leading zero, '09000' will became '9000' (seem like those value is treat as number instead of string). Even I using CAST function, it is still not working.
I doing a little testing using this code:
DECLARE #CODE VARCHAR(10) = '09000:09502';
DECLARE #Split1 VARCHAR(10) = '';
DECLARE #Split2 VARCHAR(10) = '';
SET #Split1 = CAST((CASE WHEN CHARINDEX(':', #CODE) > 0
THEN LEFT(#CODE, CHARINDEX(':', #CODE) - 1)
ELSE -1
END) AS VARCHAR(20))
SET #Split2 = LEFT(#CODE, 5);
PRINT(#Split1);
PRINT(#Split2);
The output I get is:
9000
09000
When I didn't using 'CASE WHEN', I can get the value what I want to, but I using 'CASE WHEN', the leading zero will be removed.
How can I preserve the leading zero value when I use CASE WHEN and LEFT function in a SQL Server stored procedure?
Thanks in advance.
All branches of a CASE statement must return the same data type.
When you return -1 at the else part, the value returned by this CASE is casted to integer so 09000 will turn to 9000.
You can change -1 to '-1'.
DECLARE #CODE VARCHAR(11) = '09000:09502';
DECLARE #Split1 VARCHAR(10) = '';
DECLARE #Split2 VARCHAR(10) = '';
SET #Split1 = CASE
WHEN CHARINDEX(':',#CODE)>0 THEN LEFT(#CODE, CHARINDEX(':', #CODE)-1)
ELSE '-1'
END
SET #Split2 = RIGHT(#CODE, LEN(#CODE)-CHARINDEX(':', #CODE));
PRINT(#Split1);
PRINT(#Split2);
This way you don't need the CAST() function.
Also you declared #CODE as VARCHAR(10) and this truncated the last char.
Change to VARCHAR(11).
Also I guess you want #Split2 to be assigned the right 5 chars of #CODE and not the left as in your code.
See the demo.
In your CASE statement, the THEN and ELSE statement's result data type should be same. But in your query the ELSE block's return result is -1, so it considering the output of the case statement is INT, so it remove the leading zero from the result and return as integer, and you are expecting the output as varchar only.
So if you are modify your ELSE block to ELSE '' END or ELSE '-1' END it will return your expected result as varchar(10).
As #Arulkumar mentioned, it is because your case statement is returning an integer. I simplified your code a bit:
DECLARE #CODE VARCHAR(10) = '09000:09502';
DECLARE #Split1 VARCHAR(10) = '';
DECLARE #Split2 VARCHAR(10) = '';
DECLARE #ColonIndex INT = CHARINDEX(':',#CODE)
SET #Split1 = CASE WHEN #ColonIndex > 0 THEN LEFT(#CODE, #ColonIndex-1)
ELSE '-1' END
SET #Split2 = LEFT(#CODE, 5);
PRINT(#Split1);
PRINT(#Split2);
Result:
You should probably just make your conversion impervious to the values, Here are some test cases: The second query is the one you can use with just the two columns, INSERT or UPDATE as you see fit
DECLARE #Codes TABLE (Code VARCHAR(20));
INSERT INTO #Codes (Code)
Values('09000:09502'),('090001:09502'),('090001:095022'),('0900022:09502'),
('090001:095021'),('0900055'),(':0900056'),('090003:'),(''),(':'),('::'),
('8:0900055'),(NULL);
DECLARE #Splitter VARCHAR(1) = ':';
SELECT
Code,
CHARINDEX(#Splitter, Code) AS SplitPoint,
CASE
WHEN CHARINDEX(#Splitter, Code) = 0 THEN 'NO splitter'
WHEN CHARINDEX(#Splitter, Code) = 1 THEN 'NO LEFT'
WHEN CHARINDEX(#Splitter, Code) > 1 THEN
LEFT(Code, CHARINDEX(#Splitter, Code) - 1)
WHEN CHARINDEX(#Splitter, Code) IS NULL THEN 'OOPS'
ELSE 'broken'
END AS Split1
,
CASE
WHEN CHARINDEX(#Splitter, Code) = 0 THEN Code
WHEN CHARINDEX(#Splitter, Code) = 1 THEN RIGHT(Code,LEN(Code)- 1)
WHEN CHARINDEX(#Splitter, Code) > 1 THEN
RIGHT(Code, LEN(Code )-1 -
LEN(LEFT(Code, CHARINDEX(#Splitter, Code) - 1))
)
WHEN CHARINDEX(#Splitter, Code) IS NULL THEN 'OOPS2'
WHEN CHARINDEX(#Splitter, Code) > 1 THEN 'NO RIGHT'
ELSE RIGHT(Code, LEN(Code)) + 'faile'
END AS Split2
,
CASE
WHEN CHARINDEX(#Splitter, Code) = 0 THEN ' no splitter'
WHEN CHARINDEX(#Splitter, Code) = 1 THEN ' =1'
WHEN CHARINDEX(#Splitter, Code) > 1 THEN ' >1'
WHEN CHARINDEX(#Splitter, Code) IS NULL THEN 'OOPS2'
WHEN CHARINDEX(#Splitter, Code) > 1 THEN 'NO RIGHT'
ELSE RIGHT(Code, LEN(Code)) + 'faile'
END AS Split2By
FROM #Codes;
-- end code
CREATE TABLE #MyTemp (Split1 VARCHAR(20),Split2 VARCHAR(20));
INSERT INTO #MyTemp (Split1, Split2)
SELECT
CASE
WHEN CHARINDEX(#Splitter, Code) = 0 THEN ''
WHEN CHARINDEX(#Splitter, Code) = 1 THEN ''
WHEN CHARINDEX(#Splitter, Code) > 1 THEN LEFT(Code, CHARINDEX(#Splitter, Code) - 1)
WHEN CHARINDEX(#Splitter, Code) IS NULL THEN Code
ELSE Code -- 'broken'
END AS Split1
,
CASE
WHEN CHARINDEX(#Splitter, Code) = 0 THEN Code
WHEN CHARINDEX(#Splitter, Code) = 1 THEN RIGHT(Code,LEN(Code)- 1)
WHEN CHARINDEX(#Splitter, Code) > 1 THEN RIGHT(Code, LEN(Code )-1 - LEN(LEFT(Code, CHARINDEX(#Splitter, Code) - 1)))
WHEN CHARINDEX(#Splitter, Code) IS NULL THEN Code
WHEN CHARINDEX(#Splitter, Code) > 1 THEN ''
ELSE Code -- 'fail'
END AS Split2
FROM TableWithUnsplitCodes;
SELECT * FROM #MyTemp
-- WHERE --clause if you need to bypass any
I have string:
010-234-336-.
and I want to return only number like:
010234336.
Does anyone know how to format this string?
Try this
Select Replace('010-234-336-', '-', '')
In case you have other string and want to only numeric portion, then try below code.
Declare #strAlphaNumeric varchar(256) = '010-abnasd234-336-'
DECLARE #intAlpha INT
SET #intAlpha = PATINDEX('%[^0-9]%', #strAlphaNumeric)
WHILE #intAlpha > 0
BEGIN
SET #strAlphaNumeric = STUFF(#strAlphaNumeric, #intAlpha, 1, '' )
SET #intAlpha = PATINDEX('%[^0-9]%', #strAlphaNumeric )
END
Select ISNULL(#strAlphaNumeric,0)
I got above solution :- Query to get only numbers from a string
SELECT CONVERT (INT,REPLACE('010-234-336-.','-',''))
SELECT Replace('010-234-336-', '-', '')
You can also cast or convert to integer if desired too.
SELECT CAST(Replace('010-234-336-', '-', '') AS INT) as value
SELECT CONVERT(INT, Replace('010-234-336-', '-', '')) as value
Here's a function I had made to let me remove all non-numeric characters from a string, but leave the result as a string. This was so I didn't lose any zeros from the beginning of the entry.
CREATE FUNCTION dbo.fnsStripToNumber
(
#inString varchar(500) = NULL
)
RETURNS varchar(500) AS
BEGIN
/***********************************************************************
Object : User Defined Scalar Function [dbo].[fnsStripToNumber]
Script Date : <date: 2016-04-20>
Author : Just Me
Description : Remove all non-numeric characters from a string.
Updates : 2016-04-20 - JustMe
Updated the script for speed.
Moved the function to follow coding standards.
Test Script :
SELECT
ODS.dbo.fnsStripToNumber('ts45my12fnc098. ') AS strNumber
***********************************************************************/
DECLARE
#strReturn varchar(500) = '',
#intEnPos int = 1
--
-- Loop through the string from beginning to end looking for any numbers.
--
WHILE #intEnPos > 0
BEGIN
--
-- This is like a progressive update SELECT statement.
-- The position of the next space is first found.
-- This updated value is used in the next variable assignment to parse the
-- string unit.
-- The starting position for the next string unit is updated.
-- Modify the string unit and update the return string.
--
SELECT
#intEnPos = PATINDEX('%[0-9]%', #inString),
#strReturn += (
CASE
WHEN #intEnPos > 0 THEN SUBSTRING(#inString, #intEnPos, 1)
ELSE ''
END
),
#inString = RIGHT(#inString, DATALENGTH(#inString) - #intEnPos)
END
--
-- Return the proper cased string.
--
RETURN #strReturn
END;
GO
The original code is from this website, but somehow, the page got lost so I cannot reference it. But here is the original code:
DECLARE #email_address VARCHAR(2000) = 'aname#acompany.com'
IF (
CHARINDEX(' ',LTRIM(RTRIM(#email_address))) = 0
AND LEFT(LTRIM(#email_address),1) <> '#'
AND RIGHT(RTRIM(#email_address),1) <> '.'
AND CHARINDEX('.',#email_address ,CHARINDEX('#',#email_address)) - CHARINDEX('#',#email_address ) > 1
AND LEN(LTRIM(RTRIM(#email_address ))) - LEN(REPLACE(LTRIM(RTRIM(#email_address)),'#','')) = 1
AND CHARINDEX('.',REVERSE(LTRIM(RTRIM(#email_address)))) >= 3
AND (CHARINDEX('.#',#email_address ) = 0 AND CHARINDEX('..',#email_address ) = 0)
)
print 'valid email address'
ELSE
print 'not valid'
From that, I was going to write a function I could call on to test formats. Figuring I would like to use this later to test for Twitter, and other social IDs, I figured I would make it a code that accepted the sting as well as the format to test.
Here is what I wrote:
CREATE FUNCTION [dbo].[TestForType](#strString VARCHAR(2000), #strFormat VARCHAR(2000))
RETURNS BIT
AS
BEGIN
--DECLARE #strString VARCHAR(2000)= 'aname#acompany.com'
DECLARE #email_address VARCHAR(2000)
--DECLARE #strFormat VARCHAR(2000) = 'email'
DECLARE #bitTrueFalse bit
SET #email_address =#strString
--SET #bitTrueFalse = If(#strFormat = 'email') BEGIN
If(#strFormat = 'email') BEGIN
IF (#email_address <> 'none#pletter.com'
AND CHARINDEX(' ',LTRIM(RTRIM(#email_address))) = 0
AND LEFT(LTRIM(#email_address),1) <> '#'
AND RIGHT(RTRIM(#email_address),1) <> '.'
AND CHARINDEX('.',#email_address ,CHARINDEX('#',#email_address)) - CHARINDEX('#',#email_address ) > 1
AND LEN(LTRIM(RTRIM(#email_address ))) - LEN(REPLACE(LTRIM(RTRIM(#email_address)),'#','')) = 1
AND CHARINDEX('.',REVERSE(LTRIM(RTRIM(#email_address)))) >= 3
AND (CHARINDEX('.#',#email_address ) = 0 AND CHARINDEX('..',#email_address ) = 0)
)
SET #bitTrueFalse = 1
ELSE
SET #bitTrueFalse = 0
END --END IF
ELSE
SET #bitTrueFalse = NULL
END --End IF
RETURN #bitTrueFalse
I got this error:
Msg 156, Level 15, State 1, Procedure TestForType, Line 41
Incorrect syntax near the keyword 'RETURN'.
I don't understand. I want it to return the value of #bitTrueFalse.
Your innermost IF doesn't have a BEGIN, so basically your END are unbalanced.
The END just before the RETURN is the one that belongs to the very first BEGIN (just after the AS) and therefore, your RETURN comes after the end of the function code. Put your RETURN before that very last END and you should be fine
Your code really looks like this:
CREATE FUNCTION [dbo].[TestForType]
(#strString VARCHAR(2000), #strFormat VARCHAR(2000))
RETURNS BIT
AS
BEGIN -- (1)
DECLARE #email_address VARCHAR(2000)
DECLARE #bitTrueFalse bit
SET #email_address = #strString
IF (#strFormat = 'email') BEGIN -- (2)
IF (#email_address <> 'none#pletter.com'
AND CHARINDEX(' ', LTRIM(RTRIM(#email_address))) = 0
.... all those other conditions ......
SET #bitTrueFalse = 1 -- no BEGIN here....
ELSE
SET #bitTrueFalse = 0
END -- END IF (2)
ELSE
SET #bitTrueFalse = NULL
END --- (1)
-- this ends up being *AFTER* the last END
RETURN #bitTrueFalse
Can i write the following query in other way?
ALTER PROC Proc_AssetManagement_SubscriptionCheck #IMEINumber NVARCHAR(100)
,#PhoneNo NVARCHAR(200)
,#SIMNo NVARCHAR(100)
,#Id INT
,#Message NVARCHAR(MAX) OUTPUT
AS
BEGIN
DECLARE #SimMessage NVARCHAR(200) = ''
DECLARE #PhoneMessage NVARCHAR(200) = ''
SET #Message = ''
SELECT #Message = (
CASE
WHEN COUNT(IMEINumber) > 0
THEN ('IMEI Already Exists\n')
ELSE ' '
END
)
FROM tblAssetSubscriptionDetails
WHERE AssetMgmtId <> #Id
AND (IMEINumber = #IMEINumber)
SELECT #PhoneMessage = (
CASE
WHEN COUNT(PhoneNo) > 0
THEN ('PhoneNo Already Exists\n')
ELSE ' '
END
)
FROM tblAssetSubscriptionDetails
WHERE AssetMgmtId <> #Id
AND (PhoneNo = #PhoneNo)
SELECT #SimMessage = (
CASE
WHEN COUNT(SimNo) > 0
THEN ('SimNo Already Exists')
ELSE ' '
END
)
FROM tblAssetSubscriptionDetails
WHERE AssetMgmtId <> #Id
AND (SIMNo = #SIMNo)
SET #Message = #Message + '' + #PhoneMessage + '' + #SimMessage
END
I want to reduce the number of queries and want to get the message in single query rather then 3 different queries. Can i do it? If so then how?
My purpose is that I want to get a message formed like this.
If IMEINumber is found in the table then it will show IMEI number already exists.
If SIm No is found in the table along with IMEINumber then it will show IMEI number already exists\nSim No already exists and so on...
Would this fit your need ? (Using a CTE: http://msdn.microsoft.com/en-us/library/ms175972.aspx. I wrote it partially in Notepad++ so I hope there aren't syntax error.)
The CTE tASD (stands for tblAssetSubscriptionDetails) gathers only the rows that will be useful. EXISTS should normally be better than Count() > 0 since it doesn't actually need to count everything.
WITH tASD(AssetMgmtId, IMEINumber, PhoneNo, SIMNo)
AS
(
SELECT AssetMgmtId, IMEINumber, PhoneNo, SIMNo
FROM tblAssetSubscriptionDetails
WHERE AssetMgmtId <> #Id
AND
(
IMEINumber = #IMEINumber
OR PhoneNo = #PhoneNo
OR SIMNo = #SIMNo
)
)
SELECT #Message = (
CASE
WHEN EXISTS (SELECT null FROM tASD WHERE IMEINumber = #IMEINumber)
THEN ('IMEI Already Exists\n')
ELSE ''
END
)
+
CASE
WHEN EXISTS (SELECT null FROM tASD WHERE PhoneNo = #PhoneNo)
THEN ('PhoneNo Already Exists\n')
ELSE ''
END
)
+
CASE
WHEN EXISTS (SELECT null FROM tASD WHERE SIMNo = #SIMNo)
THEN ('SimNo Already Exists')
ELSE ''
END
)
I am trying to write a function which can tell me whether there is something after second ; in the string or not.For example: the sample string is "2:00AM;3:00PM;". So the function in this case needs to return false.
Assuming that there'll always be a second ;, and no third one, this ought to work...
CREATE FUNCTION dbo.fn_Bob(#str VARCHAR(20)) RETURNS BIT
BEGIN
RETURN CASE WHEN #str LIKE '%;' THEN 0 ELSE 1 END
END
The CHARINDEX has an optional parameter to choose the start position, so find the first index of the ";" and add 1 that will start at the next character and then check for the next index and the length should be longer.
DECLARE #stringToTest nvarchar(100)
SET #stringToTest = '2:00AM;3:00PM;';
IF(LEN(#stringToTest) > CHARINDEX(';', #stringToTest, CHARINDEX(';', #stringToTest) + 1))
BEGIN
PRINT 'Yes'
END
ELSE
BEGIN
PRINT 'No'
END
create function [dbo].[udf_IsValidCheck](#Value varchar(64)) returns bit
as
begin
declare #IsValidCheck bit
select #IsValidCheck = (case when charindex( ';', #Value, charindex(';', #Value) + 1) > 0
and charindex( ';', #Value, charindex(';', #Value) + 1) < len(#Value) then 1
else 0 end)
return #IsValidCheck
end
test data:
'2:00AM;3:00PM;' --returns 0
'2:00AM;3:00PM' --returns 0
'2:00AM;3:00PM;3rdValue;4thValue;' --returns 1
'2:00AM;3:00PM;3rdValue;' --returns 1
'2:00AM;3:00PM;3rdValue' --returns 1
'2:00AM;' -- returns 0
'2:00AM;' -- returns 0