I am working on a function that will be used by no less than 10 SProc's, and will probably grow once it is ironed out.
Problem i am running into is that i do not want to develop a function for each Data Type, which is why the SQL_VARIANT data type is looking pretty convenient for the action. I know is can do the ISNULL check on the data type but i also want to check to see if the Value being passed is a valid Number but the ISNUMERIC function does not work with SQL_VARIANT and I'm not too sure about the SQL_VARIANT_PROPERTY function.
Code so far:
CREATE FUNCTION dbo.mpt_Format_Number
(
#value SQL_VARIANT
, #money BIT
)
RETURNS VARCHAR
AS
BEGIN
--Check for NULL value
IF ISNULL(#value) BEGIN
-- Value IS NULL, return NULL
RETURN NULL
END ELSE BEGIN
-- Value is NOT NULL
DECLARE #TMP VARCHAR
END
END
CREATE FUNCTION dbo.mpt_Format_Number
(
#value SQL_VARIANT
, #money BIT
)
RETURNS VARCHAR
AS
BEGIN
--Check for NULL value
IF #value is null
-- Value IS NULL, return NULL
RETURN NULL
ELSE
BEGIN
-- Value is NOT NULL
if isnumeric(convert(varchar(max), #value)) = 1 RETURN 'Y' -- is valid number
--DECLARE #TMP VARCHAR
END
return 'N' --is not valid number
END
You can always test the property type with this syntax. Should be easy to incooperate in your function.
declare #t SQL_VARIANT
set #t = '3'
select SQL_VARIANT_PROPERTY(#t, 'basetype')
Result:
varchar
As a final implementation here is the full function as it was used.
ALTER FUNCTION [dbo].[_mpt_Format_Number]
(
#value SQL_VARIANT
, #money BIT = 0
)
RETURNS VARCHAR(max)
AS
BEGIN
DECLARE #ret VARCHAR(MAX)
--Check for NULL value
IF #value IS NULL BEGIN
-- Value IS NULL, return NULL
SET #ret = 'NULL'
END ELSE BEGIN
-- Value is NOT NULL
--Check for Numeric Value
IF ISNUMERIC(CONVERT(VARCHAR, #value)) = 0 BEGIN
--Value is NOT a Number, return NULL
SET #ret = 'NULL'
END ELSE BEGIN
--Value IS a Number
declare #isNeg BIT
declare #tmp varchar(max)
set #tmp = convert(varchar(max), round(cast(#value as money), 0), 1)
--Check if value is negative
if #value < 0 begin
--Value is Negative
set #isNeg = 1
--Remove the negative sign
set #tmp = replace(#tmp, '-', '')
end
--Remove the decimal plus any digits to the right of the decimal
set #tmp = left(#tmp ,len(#tmp) - 3)
--Is money set to True
if #money = 1 begin
--Pre-pend the dollar sign to value
set #tmp = '$' + #tmp
end
--Is isNeg set to True
if #isNeg = 1 begin
--Encapsulate the value with parenthesis
set #tmp = '(' + #tmp + ')'
end
SET #ret = #tmp
END
END
RETURN #ret
END
Related
Can anyone explain to me why the following returns 'Not equal'?
DECLARE #X15 varchar(15) = 'ABC'
DECLARE #X varchar = #X15
SELECT CASE WHEN #X = #X15 THEN 'Equal' ELSE 'Not equal' END
I must be missing something obvious.
If you print out #X you'll see the problem:
DECLARE #X15 varchar(15) = 'ABC'
DECLARE #X varchar = #X15
SELECT LEN(#X), #X, CASE WHEN #X = #X15 THEN 'Equal' ELSE 'Not equal' END
If you don't specify a length for varchar it defaults to 1 character so your #X variable can only hold the first character of #X15.
The default value of n is 1 for the char and varchar data types when they are used in variable declaration.
Ex:-
DECLARE #myVariable AS varchar = 'abc';
DECLARE #myNextVariable AS char = 'abc';
DECLARE #myVariableWithLength AS varchar(15) = 'abc';
--The following returns 1
SELECT DATALENGTH(#myVariable), DATALENGTH(#myNextVariable),DATALENGTH(#myVariableWithLength);
GO
I am stuck to get output from function that takes an input parameter and should return zero or not:
alter function dbo.ZERONOT(#input int)
returns varchar(30)
as
begin
declare #result varchar(30)
declare #result1 varchar(30)
select #input = P_PRICE
from Product_ID
if (#input > 0)
set #result = 'YES'
return #result
else
set #result1 = 'NO'
return #result1
end
I think you want this:
ALTER FUNCTION dbo.ZERONOT(#Input INT) --The input value stored here
-- The variable used to pass the value to the function and make some
-- operations based on it, do not change his value.
RETURNS VARCHAR(3)
AS
BEGIN
DECLARE #Result VARCHAR(3);
IF EXISTS (SELECT 1 FROM Products WHERE Product_ID = #Input)
--Or maybe the price because I don't think you have a table named Product_ID
SET #Result = 'Yes'
ELSE
SET #Result = 'No';
RETURN #Result
END
Don't forget to visit the documentation
I am getting error while executing below query in sql server 2012:
DECLARE #Id NVARCHAR(max) = 2147483648
DECLARE #Result BIGINT = 0
IF (
#Id = 0
OR #Id = ''
)
BEGIN
SET #Result = NULL
END
ELSE
BEGIN
SET #Result = convert(bigint,#id)
END
Output:
Msg 248, Level 16, State 1, Line 3 The conversion of the nvarchar
value '2147483648' overflowed an int column.
Can someone suggest me why it is happening ?
Thanks in advance
Converting 0 to bigint will work because by default 0 will be treated as INT
DECLARE #Id NVARCHAR(max) = 2147483648
DECLARE #Result BIGINT = 0
IF ( #Id = cast(0 as bigint) -- or = '0'
OR #Id = '' )
BEGIN
SET #Result = NULL
END
ELSE
BEGIN
SET #Result = CONVERT(BIGINT, #id)
END
You have to use '' when setting #id = '0' in following:
DECLARE #Id NVARCHAR(max) = 2147483648
DECLARE #Result BIGINT = 0
IF (
#Id = '0'
OR #Id = ''
)
BEGIN
SET #Result = NULL
END
ELSE
BEGIN
SET #Result = convert(bigint,#id)
END
When you compare varchar with int. varchar is converted to int before comparison.
When an operator combines two expressions of different data types, the
rules for data type precedence specify that the data type with the
lower precedence is converted to the data type with the higher
precedence. If the conversion is not a supported implicit conversion,
an error is returned.
When #ID (= '2147483648') converted to int it exceeds the max limit of int. hence you got the error;
int
-2^31 (-2,147,483,648) to 2^31-1 (2,147,483,647) 4 Bytes
Solution:
Convert to both to varchar
IF (#Id = '0' OR #Id = '' )
Convert #Id to bigint.
IF ( convert(bigint, #Id) = 0 OR #Id = '' )
I have fields with values of a mix of both Upper case and Lower Case characters.
I am trying to return just the Upper case values as one result and likewise return just the lower case values in another. I am not trying to convert one to the other, just return the current data as is.
I cant seem to find a statement to do this and "SUBSTRING" will only return the value I specify i.e. the first and last characters
So for example if I have AAbbCCdd and want to return the upper case values, the result I need is AACC.
With a function:
CREATE FUNCTION [dbo].[GetCased](#BUFFER VARCHAR(MAX), #GETUPPER BIT) RETURNS VARCHAR(MAX) AS
BEGIN
DECLARE #LEN INT = LEN(#BUFFER), #POS INT = 1, #CHAR CHAR(1), #RESULT VARCHAR(MAX) = ''
WHILE #POS <= #LEN BEGIN
SET #CHAR = SUBSTRING(#BUFFER, #POS, 1)
SET #RESULT += CASE WHEN #CHAR COLLATE Latin1_General_CS_AS =
CASE WHEN #GETUPPER = 1 THEN UPPER(#CHAR) ELSE LOWER(#CHAR) END COLLATE Latin1_General_CS_AS THEN #CHAR ELSE '' END
SET #POS += 1
END
RETURN #RESULT
END
...
select
dbo.GetCased('AAbbCCdd', 1) as 'all upper',
dbo.GetCased('AAbbCCdd', 0) as 'all lower'
Or
CREATE FUNCTION [dbo].[fnRemovePatternFromString](#BUFFER VARCHAR(MAX), #PATTERN VARCHAR(128)) RETURNS VARCHAR(MAX) AS
BEGIN
DECLARE #POS INT = PATINDEX(#PATTERN, #BUFFER COLLATE Latin1_General_CS_AS)
WHILE #POS > 0 BEGIN
SET #BUFFER = STUFF(#BUFFER, #POS, 1, '')
SET #POS = PATINDEX(#PATTERN, #BUFFER COLLATE Latin1_General_CS_AS)
END
RETURN #BUFFER
END
...
select
dbo.fnRemovePatternFromString('AAbbCCdd ', '%[ABCDEFGHIJKLMNOPQRSTUVWXYZ]%') as 'all lower'
dbo.fnRemovePatternFromString('AAbbCCdd ', '%[abcdefghijklmnopqrstuvwxyz]%') as 'all upper'
(Cannot use [a-z])
Here's another way using functions:
CREATE FUNCTION [dbo].returnUppers
(
#str AS varchar(Max)
)
RETURNS varchar(MAX)
AS
BEGIN
DECLARE #len INT
DECLARE #cc INT = 1
DECLARE #return VARCHAR(MAX) = ''
SELECT #len = LEN(#str)
WHILE #len >= #cc
BEGIN
IF UPPER(SUBSTRING(#str,#cc,1)) = SUBSTRING(#str,#cc,1) COLLATE sql_latin1_general_cp1_cs_as
SELECT #return = #return + SUBSTRING(#str,#cc,1)
SET #cc += 1
END
RETURN #return
END
GO
To use:
DECLARE #string VARCHAR(20) = 'AAbbCCdd'
SELECT dbo.returnUppers(#string)
Returns AACC. You need to write a similar function for lowers just change UPPER() to LOWER()
As has been mentioned in the comments - this should really be done in the presentation layer, not in SQL.
However, that doesn't stop it being a bit of fun!
The key is to use a case-sensitive collation. In this example I've gone for SQL_Latin1_General_CP1_CS_AS (the "CS" = CaseSensitive. "CI" = CaseInsensitive)
You're never going to get good performance with this kind of thing though as the solution involves looping (recursive CTE in this case)
DECLARE #t table (
a char(10)
);
INSERT INTO #t (a)
VALUES ('AbC')
, ('ABCDEFGHIJ')
, ('aBCdEFghij')
, ('AbcdefhhiJ')
, ('ABcdEFGhij')
;
--SELECT a
-- , a COLLATE SQL_Latin1_General_CP1_CS_AS As case_sensitive_collation
-- , Replace(a COLLATE SQL_Latin1_General_CP1_CS_AS, 'A', '#') As case_sensitive_replace
--FROM #t
--;
; WITH characters_to_replace AS (
SELECT number
, Char(number) As c
, Row_Number() OVER (ORDER BY number) As sequence
FROM dbo.numbers
WHERE number BETWEEN 1 AND 255 -- basic characters
AND number NOT BETWEEN 65 AND 90 -- Exclude capital A-Z
)
, replacements AS (
SELECT a As original_value
, Cast(a COLLATE SQL_Latin1_General_CP1_CS_AS As nvarchar(max)) As new_value
, Cast(0 As bigint) As sequence
FROM #t
UNION ALL
SELECT replacements.original_value
, Cast(Replace(replacements.new_value, characters_to_replace.c, '') As nvarchar(max))
, characters_to_replace.sequence
FROM replacements
INNER
JOIN characters_to_replace
ON characters_to_replace.sequence = replacements.sequence + 1
)
SELECT original_value
, new_value
FROM replacements
WHERE sequence = (SELECT Max(sequence) FROM characters_to_replace)
OPTION (MaxRecursion 255)
;
I want to toggle case of entire string.
I am able to do for characters, not for string.
DECLARE #Char AS VARCHAR(1)
SET #Char='a'
IF ASCII(#Char)>=97 AND ASCII(#Char) <=122
PRINT UPPER(#Char)
IF ASCII(#Char)>=65 AND ASCII(#Char) <=90
PRINT LOWER(#Char)
How, I can change case for entire string?
For Ex. "AbCdE", I want to change it to "aBcDe".
You can do it by creating functions:
First make function for one character:
CREATE FUNCTION ToggleChar
(
#Char VARCHAR(1)
)
RETURNS VARCHAR(1)
AS
BEGIN
RETURN CHAR(ASCII(UPPER(#Char))+ASCII(LOWER(#Char))-ASCII(#Char))
END
Then, create function for string:
CREATE FUNCTION ToggleCase
(
#Str VARCHAR(MAX)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #ResultStr VARCHAR(MAX)
SET #ResultStr=''
WHILE ( #Str<>'')
BEGIN
SET #ResultStr=#ResultStr + [dbo].[ToggleChar](#Str)
SET #Str= SUBSTRING(#Str,2,LEN(#Str))
END
RETURN #ResultStr
END
Now, use this function to toggle string.
SELECT dbo.ToggleCase('AbCdE') AS ToggleString
Try this:
DECLARE #Name VARCHAR(10) = 'SaMplE'
DECLARE #Count INT = 1
WHILE #Count <= LEN(#Name)
BEGIN
SET #Name = STUFF(#Name, #Count, 1,
CASE
WHEN ASCII(SUBSTRING(#Name,#Count,1)) BETWEEN 97 AND 122 THEN
UPPER(SUBSTRING(#Name,#Count,1))
WHEN ASCII(SUBSTRING(#Name,#Count,1)) BETWEEN 65 AND 90 THEN
LOWER(SUBSTRING(#Name,#Count,1))
END)
SET #Count = #Count + 1
END
SELECT #Name