declare #institution varchar(10) = 'a', #num numeric(10,1) = 200.1
RAISERROR ('Start of strength_senior_update, #institution = %s', 0, 1,
#institution);
RAISERROR ('Start of strength_senior_update, #institution = %s, #num=%s', 0, 1,
#institution,#num);
the first RAISEERROR show expect result
Start of strength_senior_update, #institution = a
but the second RAISEERROR return error as below
The data type of substitution parameter 2 does not match the expected
type of the format specification.
anyway, there is no format specification for numeric datatype, so how to use raiseerror with numeric parameter? must declare a varchar variable and then cast the #num to that varchar variable first?
if so trouble, why not I use print instead?
there is no format specification for numeric datatype, so how to use
raiseerror with numeric parameter? must declare a varchar variable and
then cast the #num to that varchar variable first?
Correct, RAISERROR format specifications are limited so the work-around is to assign formatted message text to a variable for use with RAISERROR. The below example gleaned from the comments uses CONCAT (to convert NULL values to empty strings) and FORMAT to display the numeric value in the format of your choosing.
DECLARE #institution varchar(10) = 'a', #num numeric(10,1) = 200.1, #message varchar(2047);
SET #message = CONCAT('Start of strength_senior_update, #institution = '
, #institution
, ', #num='
, FORMAT(#num, '0.0')
);
RAISERROR (#message, 0, 1);
if so trouble, why not I use print instead?
There is no value in using RAISERROR instead of PRINT for severity zero informational messages unless you want to use the NOWAIT option or substitution parameters. PRINT allows you to specify the message expression directly without the need to assign to variable:
DECLARE #institution varchar(10) = 'a', #num numeric(10,1) = 200.1;
PRINT CONCAT('Start of strength_senior_update, #institution = '
, #institution
, ', #num='
, FORMAT(#num, '0.0')
);
Related
I have a table with a bigint column that I'm attempting to get an insert working for. We've been having issues where data that can't be converted to a numeric comes in and the insert fails. This is mostly things like spaces or line returns in the data i.e. " 123", "1 365".
Since I don't have access to the software that is attempting to insert this bad data, I thought that creating an instead of trigger and using a function to strip out all non-numeric characters would fix the issue.
This is a basic idea of what the trigger is doing.
TRIGGER [dbo].[Delivery_Before_TRG]
ON [dbo].[Delivery]
instead of INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [dbo].[Delivery]
(....,[pin],....)
select ....
,[dbo].[udf_GetNumericOnly](inserted.pin)
,....
from inserted;
END
And this is the udf_GetNumberOnly function.
FUNCTION [dbo].[udf_GetNumericOnly]
(
#Value varchar(500)
)
RETURNS bigint
AS
BEGIN
Declare
#Pos tinyint,
#Char char(1)
Set #Value = REPLACE(#Value, ' ', '') -- Strip all spaces
Set #Pos = LEN(#Value) -- Give some non-zero value
While #Pos > 0
Begin
Set #Pos = PATINDEX('%[^0-9]%', #Value) )
If #Pos > 0
Begin
Set #Char = SUBSTRING(#Value, #Pos, 1) -- Non numeric character
Set #Value = REPLACE(#Value, #Char, '')
End
End
Set #Value = RTrim(LTrim(#Value))
Return convert(bigint,#Value)
END
I can run the function and it will strip all non-numeric characters for anything that I pass it, however, when I attempt to run an insert statement into my table I get a Msg 8114, Level 16, State 5, Line 4
Error converting data type varchar to bigint. error.
From what I can tell the problem is something to do with sql server checking that the fields I'm attempting to to insert match the destination table column datatypes before my trigger gets a hold of the data to convert it. I know this because I had modified the trigger to insert a number directly into the pin field and would still get this error.
Additionally, I know it isn't the function failing because I can write an insert that will fail and then change that insert to call the function, and it will work.
--This fails
INSERT INTO (....,pin,...)
VALUES(....,'1a23',....)
--This works
INSERT INTO (....,pin,...)
VALUES(....,udf_GetNumericOnly('1a23'),....)
Yeah, the algebrizer looks at the data types in your query right after the parser makes sure you've written valid sql. The INSTEAD OF INSERT trigger fires for each row that would be inserted, which an invalid cast wouldn't be.
I've declared a variable in a stored procedure:
DECLARE #CurrentChunk NVARCHAR(250)
I would like to use the length of the variable, i.e. 250, later in my sp for computational purposes, and I want to keep my code as dry as possible.
Here's my code (assume #Narrative is a param to the SP):
DECLARE #ChunkSizeCharacters INT,
#NumChunks INT,
#LoopIndex INT,
#CurrentChunk NVARCHAR(250)
SET #ChunkSizeCharacters = 250 -- HERE'S WHERE I WANT THE LENGTH OF #CurrentChunk
SET #NumChunks = CEILING((LEN(#Narrative) * 1.0)/#ChunkSizeCharacters)
SET #LoopIndex = 0;
WHILE (#LoopIndex < #NumChunks)
BEGIN
SET #CurrentChunk = SUBSTRING(#Narrative,
((#LoopIndex * #ChunkSizeCharacters) + 1), #ChunkSizeCharacters)
INSERT INTO [dbo].[Chunks] ([Chunk]) VALUES (#CurrentChunk)
SET #LoopIndex = #LoopIndex + 1
END
Is there a way to ascertain the length of an NVARCHAR or VARCHAR variable definition (please read carefully -- I'm not looking for LEN())?
It seems the MaxLength variant property returns the value you're looking for.
DECLARE #Banana varchar(255) = 'This banana'
SELECT SQL_VARIANT_PROPERTY(#Banana, 'MaxLength')
Returns 255.
If you don't mind overwriting the variable (and if you do, you can assign it to a temp NVARCHAR(MAX)):
SELECT #CurrentChunk = REPLICATE(0, 8000);
SELECT #ChunkSizeCharacters = LEN(#CurrentChunk);
This trick does not and cannot work for NVARCHAR(MAX), but that's presumably no problem, given it's enormous maximum size.
Unfortunately T-SQL has nothing in the way of metadata properties for variables. Even determining the type of an expression is a chore.
Interestingly, the value returned by that SELECT SQL_VARIANT_PROPERTY statement doesn't select into a plain, predefined variable. In the end, I used:
DECLARE #Text VARCHAR(400), #TextLen INT
SELECT #TextLen = CAST(SQL_VARIANT_PROPERTY(ISNULL(#Text, ''), 'MaxLength') AS INT)
Works like a charm for me!
I have the following procedure;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
--re runnable.
IF EXISTS (SELECT 1 FROM sys.objects WHERE name = 'spGetMessageArray' AND type = 'P' )
BEGIN
DROP PROCEDURE dbo.spGetMessageArray
END
GO
CREATE PROCEDURE dbo.spGetMessageArray
#message VARCHAR(50),
#messageArray VARCHAR(50) OUTPUT
AS
BEGIN
SET NOCOUNT ON
SELECT #messageArray = (SELECT CAST(MessageId AS VARCHAR(5))+','
FROM Messages
WHERE Message = #message
FOR XML Path(''))
-- Remove trailing comma if necessary
SELECT #messageArray = LEFT(#messageArray, LEN(#messageArray) - 1)
RETURN #messageArray
END
When I run this as just a query (not as an sp), I get the results I want (33, 44, 53) as a comma separated string.
When I call this using;
DECLARE #message VARCHAR(50) = 'Safety'
DECLARE #messageArray VARCHAR(50) =''
EXEC dbo.spGetMessageArray #message, #messageArray = #messageArray OUTPUT
PRINT #messageArray
I get an error:
Conversion failed when converting the varchar value '33,44,53' to data type int.
Can anyone explain what I'm misunderstanding. I'm guessing the INT is some form of count of rows affected or something. I'm just so confused by that damn int. As far as I can tell, I'm just using VARCHAR
I am trying to return the prefix of a VAT number with a SQL function. Because of some changes in these numbers and differences in countries and mistakes in the database, the length of the prefix differs from 0 to 4 characters. So the input of my function is a string, with a prefix of not numeric characters and then some numbers. For example ES012345678, and then i only want to return ES.
I wrote a function for it and it fails, it only returns NULL, even when the input is like the example.
Anyone knows where my mistake is?
here is my SQL code:
ALTER FUNCTION [dbo].[returnPreOfVat]
(
-- Add the parameters for the function here
#VATstring varchar
)
RETURNS varchar
AS
BEGIN
-- Declare the return variable here
DECLARE #Result varchar
DECLARE #char varchar(2)
DECLARE #counter int
SET #counter =1;
SET #char = '';
WHILE (#counter < 5) --check some from the front
BEGIN
SET #char = SUBSTRING(#VATstring, #counter,1); --get next char from front
IF(ISNUMERIC(#char)<>1) -- not numeric
BEGIN
SET #Result = #Result + #char;
END
SET #counter=#counter+1;
END
-- Return the result of the function
RETURN #Result
END
you never initialize the result , Please try:
DECLARE #Result varchar = ''
If recall correctly NULL + str = NULL.
I think a loop is overkill here. I'd combine the LEFT and PATINDEX functions
select LEFT(#VATstring, PATINDEX('%[0-9]%', #VATstring)-1)
I have seen this question all over stackoverflow, but it seems that there are a wide number of solutions tailored to the situation. It seems I have a unique situation as far as I can tell. I am running this sql statement
use IST_CA_2_Batch_Conversion
GO
--T-SQL script to populate the Match type column
declare #MatchType varchar(16),
#PK varchar(500),
#CAReturnCode VARCHAR(255),
#CAErrorCodes VARCHAR(255)
declare cursor1 cursor fast_forward for
select
["Ref#"],
["Return Code"],
["Error Codes"]
from CACodes2MatchType
open cursor1
fetch next from cursor1 into #PK,#CAReturnCode,#CAErrorCodes
while ##fetch_status = 0
begin
set #MatchType = dbo.GetMatchType(#CAReturnCode,#CAErrorCodes)
update CACodes2MatchType
set [Match Type] = #MatchType
where ["Ref#"] = #PK
fetch next from cursor1 into #PK,#CAReturnCode,#CAErrorCodes
end
close cursor1
deallocate cursor1
It will fail at
set #MatchType = dbo.GetMatchType(#CAReturnCode,#CAErrorCodes)
Here is the beginning code for the GetMatchType function:
-- Batch submitted through debugger:
SQLQuery14.sql|6|0|C:\Users\b01642a\AppData\Local\Temp\~vs1C8E.sql
CREATE FUNCTION [dbo].[GetMatchType](#CAReturnCode VARCHAR(255), #CAErrorCodes
VARCHAR(255))
RETURNS VARCHAR(16)
BEGIN
DECLARE #MatchType VARCHAR(16);
DECLARE #errorCodes TABLE(Pos INT, Code CHAR(2));
DECLARE #country INT; -- 1 is US, 2 is Canada
DECLARE #numMinorChanges INT;
DECLARE #numMajorChanges INT;
DECLARE #numSingleCodes INT;
DECLARE #returnCode INT;
DECLARE #verified VARCHAR(16);
DECLARE #goodFull VARCHAR(16);
DECLARE #tentativeFull VARCHAR(16);
DECLARE #poorFull VARCHAR(16);
DECLARE #multipleMatch VARCHAR(16);
DECLARE #unmatched VARCHAR(16);
SET #verified = 'Verified';
SET #goodFull = 'Good Full';
SET #tentativeFull = 'Tentative Full';
SET #poorFull = 'Poor Full';
SET #multipleMatch = 'Multiple Match';
SET #unmatched = 'Unmatched';
SET #returnCode = CAST(#CAReturnCode AS INT);
I will get the error: Msg 245, Level 16, State 1, Line 21
Conversion failed when converting the varchar value '"1"' to data type int.
This error occurs at the last line of the code segment I have shown:
SET #returnCode = CAST(#CAReturnCode AS INT);
This is code that was written by a colleague and supposedly had worked for him. I have had to troubleshoot some errors but I cannot debug this one. I understand alot of people will create a dbo.split function? I don't know if this option will help me in this scenario. I have tried setting #returnCode to a varchar and getting rid of the CAST on #CAReturnCode. As a result, the debugger will make it past that line but raises issues with the rest of the code. I am assuming there is an issue with how I am casting #CAReturnCode? Any help would be much appreciated.
The problem is that #CAReturnCode contains non-numeric characters.
-- Msg 245, Level 16, State 1, Line 21 Conversion failed when converting the varchar value '"1"' to data type int.
See, the outer single quotes are the error message's formatting, but the inner double quotes are in the #CAReturnCode value. So the solution here is to ensure that the variable contains only numeric characters prior to converting. If double quotes are the only possibility, you can do a quick and dirty fix like this:
set #returnCode = cast(replace(#CAReturnCode, '"', '') as int)
If there are more possibilities, you could do multiple REPLACE calls, or you could build a better character-trimming function that will remove all the characters you specify at once yourself.