TSQL - Conversion failed on Output parameter - sql-server

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

Related

Cannot see expected PRINT or RAISERROR output when a later error is raised

I'm getting an error message in a stored procedure, saying that I can't insert a NULL value into a table, when I should be getting errors earlier in the code if the value is null.
Here's the relevant part of the stored procedure:
CREATE PROCEDURE [dbo].[udp_AddUpdateStaffVariable]
-- Add the parameters for the stored procedure here
#StaffID int=null,
#VariableTypeID int,
#VariableIntValue int=null,
#VariableVarcharValue varchar(max)=null,
#VariableDatetimeValue datetime=null,
#VariableDecimalValue decimal=null
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
BEGIN TRY
DECLARE #PrintOutput varchar(150)
SET #PrintOutput = '#StaffID = ' + CASE WHEN #StaffID = NULL THEN 'Null' ELSE CONVERT(varchar(20), #StaffID) END
RAISERROR (#PrintOutput, 10, 1) WITH NOWAIT
IF (#StaffID = NULL) -- If the staffid of the current user was not supplied, find it in the Staff table
BEGIN
DECLARE #CurrentUser nvarchar(255) = SUSER_SNAME();
SELECT #StaffID = [StaffID] FROM [dbo].[Staff] WHERE [UserName] = #CurrentUser;
SET #PrintOutput = '#StaffID = ' + CASE WHEN #StaffID = NULL THEN 'Null' ELSE CONVERT(varchar(20), #StaffID) END
RAISERROR (#PrintOutput, 10, 1) WITH NOWAIT
IF #StaffID = NULL -- raise error if staffid wasn't found
BEGIN
RAISERROR (50001 --error number
, 16 -- severity
, 1 --state
, #CurrentUser -- parameter
)
END
END
-- Get the variable data type (used to determine where the variable is stored)
DECLARE #VarDataTypeDesc varchar(20)
DECLARE #StaffVarID int
SELECT #VarDataTypeDesc = dt.[StaffVariableDataType]
FROM [list].[DataTypes] dt INNER JOIN [list].[StaffVariableTypes] svt ON dt.DataTypeID = svt.DataTypeID
WHERE svt.VariableTypeID = #VariableTypeID
-- update or add the staff variable
IF EXISTS (SELECT 1 FROM [dbo].[StaffVariables] WHERE StaffID = #StaffID AND [VariableTypeID] = #VariableTypeID) -- update
BEGIN
IF #VarDataTypeDesc = 'int'
BEGIN -- only update here - other data types are updated further down
UPDATE [dbo].[StaffVariables] SET VariableIntValue = #VariableIntValue WHERE StaffID = #StaffID AND VariableTypeID = #VariableTypeID
END
ELSE -- StaffVariableID is only needed if the variable type is not int
BEGIN
SELECT #StaffVarID = StaffVariableID FROM [dbo].[StaffVariables] WHERE StaffID = #StaffID AND [VariableTypeID] = #VariableTypeID
END
END
ELSE -- insert
BEGIN
IF #VarDataTypeDesc = 'int'
BEGIN
INSERT INTO [dbo].[StaffVariables] (StaffID, VariableTypeID, VariableIntValue)
VALUES (#StaffID, #VariableTypeID, #VariableIntValue)
END
ELSE -- StaffVariableID is only needed if the variable type is not int
BEGIN
DECLARE #StaffVarIDTbl table(ID int)
INSERT INTO [dbo].[StaffVariables] (StaffID, VariableTypeID, VariableIntValue)
OUTPUT INSERTED.[StaffVariableID] INTO #StaffVarIDTbl
VALUES (#StaffID, #VariableTypeID, #VariableIntValue)
SELECT #StaffVarID = ID FROM #StaffVarIDTbl
END
END
-- Cutting out the section where I deal with other variable types besides int here - not relevant to this problem
END TRY
BEGIN CATCH
DECLARE #ErrorMessage NVARCHAR(4000);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
SELECT
#ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
-- Use RAISERROR inside the CATCH block to return error
-- information about the original error that caused
-- execution to jump to the CATCH block.
RAISERROR (#ErrorMessage, -- Message text.
#ErrorSeverity, -- Severity.
#ErrorState -- State.
);
END CATCH;
END
Here's the test procedure run code:
DECLARE #return_value int
EXEC #return_value = [dbo].[udp_AddUpdateStaffVariable]
#VariableTypeID = 1,
#VariableIntValue = 10
SELECT 'Return Value' = #return_value
GO
...and here's the response:
Msg 50000, Level 16, State 2, Procedure dbo.udp_AddUpdateStaffVariable, Line 130 [Batch Start Line 2]
Cannot insert the value NULL into column 'StaffID', table 'SnippingDbName.dbo.StaffVariables'; column does not allow nulls. INSERT fails.
(1 row affected)
Completion time: 2020-06-01T21:17:08.2049072-05:00
So... here's the question. The error seems to indicate that it either never ran the whole, if #StaffID = NULL portion of the code, or it did, and didn't find the StaffID and set the #StaffID variable. But if that were the case, why can't I see the results of my earlier RAISERROR statements?
I initially tried PRINT and switched to RAISERROR when PRINT wasn't working.
SQL Server 2017 Developer Edition, SSMS 15.0.18183.0
It was a syntax error, that people commenting on the question figured out. IF (#StaffID = NULL) should have been, IF (#StaffID IS NULL) Fixing that in all places in the procedure fixed the problem, and altering my test Staff record so UserName doesn't match SUSER_SNAME() resulted in the expected error.

How Do I Solve Error "Expects Parameter" for stored procedure

I am getting this error
Msg 201, Level 16, State 4, Procedure sp_GetAllAirports, Line 0 [Batch Start Line 2]
Procedure or function 'sp_GetAllAirports' expects parameter '#AirportID', which was not supplied."
When I run
EXEC sp_GetAllAirports
The following is my stored procedure which shows #AirportID, what could be the issue?
IF OBJECT_ID('sp_GetAllAirports', 'P') IS NOT NULL
DROP PROCEDURE [dbo].[sp_GetAllAirports]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[sp_GetAllAirports]
#AirportID INT,
#ICAOCode VARCHAR(4) NULL,
#AirportName VARCHAR(MAX),
#City VARCHAR(MAX),
#Lat DECIMAL(8,3),
#Long DECIMAL (11,3),
#Elevation INT,
#Country NVARCHAR(MAX)
AS
BEGIN TRANSACTION
BEGIN TRY
SET NOCOUNT ON
SET ANSI_WARNINGS OFF
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
--SELECT * FROM tbl_Airports ORDER BY AirportID ASC
SELECT
AirportID, ICAOCode, AirportName, City,
Latitude, Longitude, Elevation, CountryFK
FROM
tbl_Airports
LEFT JOIN
tbl_Countries ON CountryID = tbl_Airports.CountryFK
WHERE
CountryID = tbl_Airports.CountryFK
ORDER BY
AirportID
END TRY
BEGIN CATCH
DECLARE #ErMessage NVARCHAR(MAX),
#ErSeverity INT,
#ErState INT
SELECT
#ErMessage = ERROR_MESSAGE(),
#ErSeverity = ERROR_SEVERITY(),
#ErState = ERROR_STATE()
IF ##TRANCOUNT > 0
BEGIN
ROLLBACK TRANSACTION
END
RAISERROR(#ErMessage, #ErSeverity, #ErState)
END CATCH
IF ##TRANCOUNT > 0
BEGIN
COMMIT TRANSACTION
END
GO
Your stored procedure is defined to expect arguments (AirportID, ICAOCode, AirportName, City, Lat, Long, Elevation and Country):
CREATE PROCEDURE [dbo].[sp_GetAllAirports]
#AirportID INT,
#ICAOCode VARCHAR(4) NULL,
#AirportName VARCHAR(MAX),
#City VARCHAR(MAX),
#Lat DECIMAL(8,3),
#Long DECIMAL (11,3),
#Elevation INT ,
#Country NVARCHAR(MAX)
AS
...
However, it doesn't use any of them. So you probably just need to remove them:
CREATE PROCEDURE [dbo].[sp_GetAllAirports]
AS
...
Alternatively, make sure the arguments are used in the SP (so it makes sense to expect arguments) and pass values accordingly (sp_GetAllAirports 1234) e.g.:
CREATE PROCEDURE [dbo].[sp_GetAllAirports]
#AirportID INT
AS
....
SELECT AirportID, ICAOCode, AirportName, City, Latitude, Longitude, Elevation, CountryFK
FROM tbl_Airports
LEFT JOIN tbl_Countries ON CountryID = tbl_Airports.CountryFK
WHERE CountryID = tbl_Airports.CountryFK
AND AirportID = #AirportID -- Using first argument here
ORDER BY AirportID
....
Or, finally, give the arguments default values, e.g:
CREATE PROCEDURE [dbo].[sp_GetAllAirports]
#AirportID INT = NULL,
#ICAOCode VARCHAR(4) = 'FOO',
...
AS
...
That way you won't have to explicitly pass any argument values. However, you'll still need to use the arguments to having the arguments make sense in the first place.

SQL Proc 'Conversion failed' from varchar to int. Why the conversion?

My question here would be... Why is it converting to int from varchar? I'm not sure what it is trying to do
CREATE PROCEDURE #myTestProcedure
(
#TransId VARCHAR(15)
)
AS
BEGIN
DECLARE #Result VARCHAR(15);
WITH TestCTE (TransId, AdjRefTransId) AS
(
SELECT TRANSID, ADJREFTRANSID
FROM dbo.MyTable
WHERE TRANSID = #TransId
UNION ALL
SELECT pet.TRANSID, pet.ADJREFTRANSID
FROM dbo.MyTable AS pet
JOIN TestCTE
ON TestCTE.ADJREFTRANSID = pet.TRANSID
)
SELECT #Result =
(
SELECT MAX(MyResult)
FROM dbo.MyOtherTable
WHERE TRANSID = TestCTE.TRANSID
)
FROM TestCTE
WHERE TestCTE.ADJREFTRANSID = ''
RETURN #Result
END
EXEC dbo.#myTestProcedure #TransId = 'MyTransId'
Error:
Msg 245, Level 16, State 1, Procedure #myTestProcedure 0004C61A, Line 32
Conversion failed when converting the varchar value 'MyResult' to data type int.
I can't see where it is trying to make this conversion. Line 32 is a blank line. No code there.
It is your RETURN. Stored procedures return an integer to indicate the status of the execution, not return values. You would either need to Select #Result OR have #Result be an output parameter.

SQL Server stored procedure evaluating JSON_VALUE out of execution order

In the below procedure, I am trying to return a value based on an input that is in JSON format. To protect against an invalid JSON input, I am using the ISJSON() function. However, SQL Server appears to be evaluating JSON_VALUE() in the 2nd statement prior to the ISJSON() validation check in the 1st statement.
CREATE TABLE dbo.Table1(
ColKey integer NOT NULL,
ColText nvarchar(255) NOT NULL,
CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED ([ColKey] ASC));
GO
INSERT INTO dbo.Table1(ColKey, ColText)
VALUES (1, 'Test String');
GO
CREATE PROCEDURE [dbo].[usp_GetTextFromJSON]
#JSON nvarchar(255),
#TextOut nvarchar(255) OUTPUT
AS
BEGIN
IF ISJSON(#JSON) <> 1
THROW 50000, 'Invalid JSON', 1; -- Alternatively: RETURN -1;
SELECT TOP 1 #TextOut = ColText
FROM dbo.Table1
WHERE ColKey = JSON_VALUE(#JSON, N'$.Col1Key')
RETURN 0;
END;
GO
Executing the procedure with an invalid JSON string does not trigger the expected exception.
DECLARE #return_value int,
#TextOut nvarchar(255);
EXEC #return_value = [dbo].[usp_GetTextFromJSON]
#JSON = N'{Col1Key:1}', -- Invalid JSON: ISJSON(N'{Col1Key:1}') = 0
#TextOut = #TextOut OUTPUT;
SELECT #TextOut;
returns:
Msg 13609, Level 16, State 1, Procedure dbo.usp_GetTextFromJSON, Line 10 [Batch Start Line 29]
JSON text is not properly formatted. Unexpected character 'C' is found at position 1.
Changing the execution code to the following returns successfully.
DECLARE #return_value int,
#TextOut nvarchar(255);
EXEC #return_value = [dbo].[usp_GetTextFromJSON]
#JSON = N'{"Col1Key":1}', -- Valid JSON
#TextOut = #TextOut OUTPUT;
SELECT #TextOut;
Why is SQL Server evaluating JSON_VALUE() in the 2nd statement before evaluating ISJSON in the 1st statement?
It''s a compilation issue not an execution issue. When you run the good one first the plan is generated and cached and the bad one then works as you want.
Probably it tries to evaluate JSON_VALUE(#JSON, N'$.Col1Key') against the initial parameter value so it can then use the histogram on ColKey to get row estimates.
You can try assigning the parameter to a local variable to avoid this.
CREATE PROCEDURE [dbo].[usp_GetTextFromJSON] #JSON NVARCHAR(255),
#TextOut NVARCHAR(255) OUTPUT
AS
BEGIN
DECLARE #vJSON NVARCHAR(255) = #JSON;
IF ISJSON(#vJSON) <> 1
THROW 50000, 'Invalid JSON', 1; -- Alternatively: RETURN -1;
SELECT TOP 1 #TextOut = ColText
FROM dbo.Table1
WHERE ColKey = JSON_VALUE(#vJSON, N'$.Col1Key')
RETURN 0;
END;

SQL Server: stored proc tries to convert varchar OUTPUT into int #Return_Value

I have this stored procedure:
create proc Sponsors.GetLightBoxAd
(
#SponsorID varchar(30),
#ADIDOut varchar(30) OUTPUT,
#UserID varchar(30),
#ProjectID varchar(50),
#PlatformID int
)
as
begin
SELECT TOP 1 #ADIDOut = AD.ADID --my output. AD.ADID is a varchar(30) column
FROM Sponsors.AD
WHERE AD.Active = 1 and AD.SponsorID = #SponsorID
ORDER by NEWID() -- I want the first one picked at random
IF ISNULL(#ADIDOut,-1) != -1 --if the result set wasn't null, run some update queries with the result
BEGIN --These queries do not have output variables.
EXEC Sponsors.proc1 #ADIDOut, #SponsorID
EXEC Projects.proc2 #ProjectID,#ADIDOut,#UserID,#PlatformID
END --end the if
end --end the proc
go
This should return either a null value or a varchar.
However when I try to execute the query, SSMS auto-generates this code for me to run the query:
USE [MyDB]
GO
DECLARE #return_value int, --Why is this here???
#ADIDOut varchar(30) -- this should be my only output
EXEC #return_value = [Sponsors].[GetLightBoxAd]
#SponsorID = N'Alienware',
#ADIDOut = #ADIDOut OUTPUT,
#UserID = N'127.0.0.1',
#ProjectID = N'TestProject',
#PlatformID = 1
SELECT #ADIDOut as N'#ADIDOut'
SELECT 'Return Value' = #return_value --why is this here?
GO
And then it gives me an error because it appears to try to convert the result of ADIDOut into an int... Why is there an int #Return_Value variable and why is it trying to put my actual OUTPUT result into it?
The error was in this line:
IF ISNULL(#ADIDOut,-1) != -1
It seems since I put just -1 without quotes as the comparison, sql reads this as an integer and cannot compare it to a nullable string so the error is raised. Putting the -1's into quotes fixes the error and the query runs. Thanks for the help!

Resources