Forward slash in stored procedure parameter not recognised - sql-server

I'm making this stored procedure call:
exec sp_executesql N'EXEC MyStoredProcedure
#MyId = #0, #MyVarField = #1',
N'#0 int, #1 nvarchar(4000)',
#0=2, #1='lll/kkk'
The stored procedure is just a simple select, looking for MyVarField = 'lll/kkk', but the / in the parameter seems to break it... it can't find the db row anyway.
If I pass in 'ffflll' then it finds the row which contains lllkkk, just doesn't find it when there's a / in it. What's that about?
ALTER PROCEDURE [dbo].[MyStoredProcedure]
#MyId int,
#MyVarField varchar
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM MyTable WHERE VarField = #VarField
END
What do I need to do to the stored procedure to make it accept the / as part of a varchar?

Try making your parameter match the same type as the statement (and presumably the underlying column), and giving it a length:
ALTER PROCEDURE [dbo].[MyStoredProcedure]
#MyId int,
#MyVarField NVARCHAR(4000)
AS
...
I don't think the failure currently has anything to do with the slash. Try this:
CREATE PROCEDURE dbo.foo
#bar VARCHAR
AS
PRINT #bar;
GO
EXEC dbo.foo '12345';
For some background, please read:
Bad habits to kick : declaring VARCHAR without (length)

Forward slash (“/” ) is the shortcut for RUN command (like “go” in mysql or sqlserver).
http://power2build.wordpress.com/2011/12/09/forward-slash-in-sqlplus/

Related

How to systematically get stored procedure (SP) parameter names and their values INSIDE the SP execution

As described in title, I am trying to systematically get stored procedure pararameter names and their corresponding values inside the execution of the proper stored procedure.
First point, which is taking stored procedure parameter names, is easy using table [sys].[all_parameters] and the stored procedure name. However, getting the actual values of these parameters is the difficult part, specially when you are not allowed to use table [sys].[dm_exec_input_buffer] (as a developer, I am not allowed to read this table, since it is a system administrator table).
Here is the code I have so far, which I am sure can serve you as a template:
CREATE PROCEDURE [dbo].[get_proc_params_demo]
(
#number1 int,
#string1 varchar(50),
#calendar datetime,
#number2 int,
#string2 nvarchar(max)
)
AS
BEGIN
DECLARE #sql NVARCHAR(MAX);
DECLARE #ParameterNames NVARCHAR(MAX) = ( SELECT STRING_AGG([Name], ',') FROM [sys].[all_parameters] WHERE OBJECT_ID = OBJECT_ID('[dbo].[get_proc_params_demo]') )
SET #sql = N'SELECT ' + #ParameterNames;
DECLARE GetParameterValues CURSOR FOR
SELECT DISTINCT [Name] FROM [sys].[all_parameters] WHERE OBJECT_ID = OBJECT_ID('[dbo].[get_proc_params_demo]');
OPEN GetParameterValues;
DECLARE #param_values NVARCHAR(MAX) = NULL
DECLARE #StoredProcedureParameter NVARCHAR(MAX)
FETCH NEXT FROM GetParameterValues INTO #StoredProcedureParameter;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #param_values = 'ISNULL('+#param_values+','')'+#StoredProcedureParameter+','
EXEC(#param_values)
FETCH NEXT FROM GetParameterValues INTO #StoredProcedureParameter;
END;
CLOSE GetParameterValues;
DEALLOCATE GetParameterValues;
SET #param_values = LEFT(#param_values, LEN(#param_values) - 1)
EXEC sp_executesql #sql,#ParameterNames,#param_values;
END
EXEC [dbo].[get_proc_params_demo]
#number1=42,
#string1='is the answer',
#calendar='2019-06-19',
#number2=123456789,
#string2='another string'
This is my approach trying to dynamically get parameter actual values inside a cursor, but it does not work, and I am clueless so far. I know it is quite rudimentary, and I am happy to hear other approaches. To be fair, I don't know if this problem is even possible to solve without system tables, but it would be great.
EDIT: This is an attempt to get a generic code that works on any stored procedure. You do not want to hardcode any parameter name. The only input you have is the stored procedure name via OBJECT_NAME(##PROCID)

Correct way to use goto statement to transfer control to a label after go

For example. The following code fails because the 'ReturnControl' label is not recognized as it is after the go statement. But I need the configuration code for the query on the top as it gets modified repeatedly and it is easier to access instead of skimming through the whole query and finding the lines that need to be changed.
I am not limited to using goto. I am open to any other suggestions or methods that would allow keeping configuration logic on top of the query.
GOTO BatchSetup;
ReturnControl:
/*
Set Parameters here.
Configuration code that gets modified repeatedly
*/
Insert ##Parameters VALUES ('SomeParam', 'paramValue')
EXEC #CreateJob 'Job1'
EXEC #CreateJob 'Job2'
EXEC #ExecuteJob 'Job1'
EXEC #ExecuteJob 'Job2'
GOTO ENDBatch;
BatchSetup:
CREATE TABLE ##Jobs
(
ID INT IDENTITY,
JobName NVARCHAR(100),
);
CREATE TABLE ##Parameters
(
ParamName NVARCHAR(100),
ParamValue NVARCHAR(100),
);
GO
CREATE OR ALTER PROC #CreateJob
#JobName NVARCHAR(100)
AS
BEGIN
INSERT ##Jobs (JobName) VALUES (#JobName);
END
GO
CREATE OR ALTER PROC #ExecuteJob
#JobName NVARCHAR(100)
AS
BEGIN
DECLARE #Param NVARCHAR(100) = (SELECT ParamValue FROM ##Parameters WHERE ParamName = 'SomeParam');
/*
Code to execute Job
*/
END
GO
GOTO ReturnControl;
ENDBatch:
DROP TABLE IF EXISTS ##Jobs;
DROP TABLE IF EXISTS ##Parameters;
DROP PROC IF EXISTS #CreateJob;
DROP PROC IF EXISTS #ExecuteJob;
Edit:
I have restructured the query based on suggestions that somewhat did the job.
/*
Setup: Create temp stored procedures and temp tables. Access value using SESSION_CONTEXT
/*
Set Parameters here.
Configuration code that gets modified repeatedly
*/
EXEC sp_set_session_context #Key = 'key1', #Value = 'value1';
EXEC sp_set_session_context #Key = 'key2', #Value = 'value2;
EXEC Job1
EXEC Job2
EXEC Cleanup

SQL Server stored procedure only works with locally re-declared variables; not variables passed to the procedure

I have edited my SQL code blocks to more accurately show what is going on
Say I have a simple stored procedure:
CREATE PROCEDURE [DBO].[FOO]
(#VARIABLE VARCHAR(500))
AS
BEGIN
SELECT AVG(BAR)
FROM MYTABLE
WHERE THING = #VARIABLE AND RTRIM(LTRIM(THING)) <> ''
END
When I call this stored procedure from my classic ASP page; which in this case would be with:
Set foo = Server.CreateObject("ADODB.RecordSet")
curCmd = "Foo 'MYVARIABLE'"
foo.Open curCmd, connectionString
I get this error (on the same line as the page opens the foo object):
Arithmetic overflow error converting varchar to data type numeric.
If I call the stored procedure manually in the terminal (IDE?); then it works fine.
Also if I recreate the stored procedure as the following:
CREATE PROCEDURE [DBO].[FOO]
(#VARIABLE VARCHAR(500))
AS
BEGIN
DECLARE #VARIABLE2 VARCHAR(500) = #VARIABLE
SELECT AVG(BAR)
FROM MYTABLE
WHERE THING = #VARIABLE2 AND RTRIM(LTRIM(THING)) <> ''
END
Then the stored procedure runs fine.
I have tried dropping and recreating the stored procedure (without using the re-declaration trick), but it does not fix the issue.
*As an aside; there is validation on the data being inserted into the table to ensure that only numbers (integers) are being entered for the THING field. The THING field can also be blank; hence the where clause.
I basically have two questions:
Why does re-declaring the same variable type with the same data fix the issue?
Is there a way I can fix my problem without using this silly "re-declaration" trick?
Thanks in advance for any help with this.
I think you can get the same error if you use begin/end:
CREATE PROCEDURE [DBO].[FOO] (
#VARIABLE VARCHAR(500)
)
AS
BEGIN
DECLARE #VARIABLE2 VARCHAR(500) = #VARIABLE;
SELECT AVG(BAR) FROM MYTABLE WHERE THING = #VARIABLE2;
END;
Then, both statements will be part of the stored procedure body and you can work on fixing the data so it will work.

No result rowset is associated with the execution of this query

I am creating an Execute SQL task in SSIS 2016 which calls an insert stored procedure. I am trying to return the id of the newly created row in the output parameter but facing the following error.
No result rowset is associated with the execution of this query
I had set the SQL Server Profiler on to see what was generated and it was as follows
declare #p4 int
set #p4=NULL
exec sp_executesql N'Exec [dbo].[InsertPkgAudit] #P1,#P2',N'#P1 varchar(16),#P2 int OUTPUT','CoreReferenceETL',#p4 output
select #p4
If I execute the following it manually it works
DECLARE #auditId INT;
EXEC [dbo].[InsertPkgAudit] #packageName = 'CoreReferenceETL', #auditId = #auditId OUTPUT;
PRINT #auditId;
So it is clear that the stored procedure is fine but some problem with the way its called in SSIS. Could somebody help ?
The Execute SQL task contains the following statement
Exec [dbo].[InsertPkgAudit] #packageName =?, #auditId = ?
The parameter mapping is as follows
The result pane is as follows
The stored procedure is as follows:
CREATE Procedure [dbo].[InsertPkgAudit]
#packageName varchar(100),
#auditId int output
AS
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[PkgAudit] ([PackageName], [StartTime])
VALUES (#packageName, GETDATE());
SET #auditId = SCOPE_IDENTITY();
END
The table structure is as follows
You have told SSIS that your procedure returns a result set. But it doesn't. It populates an OUTPUT parameter instead.
You can either change your proc to return a resultset, or you can modify the Execute task and
Specify No Result Set
Change the query to this:
`Exec [dbo].[InsertPkgAudit] #packageName =?, #auditId = ? OUTPUT`
I just had a similar issue and while looking for some sort of solution I came across this old post. I wasn't able to find the solution online but, here is how I resolved my issue. I hope this helps folks in the future.
If you really need to get the data passed via RowSet, you will need to select as
'ColumnName'.
Declare #fname varchar(50)
Declare #lname varchar(50)
set #fname ='John'
set #lname= 'Doe'
select #fname, #lname--without column name
select #fname as 'firstName', #lname as 'LastName'--with column name
Here is how they would show up in the results.
You can now map the result to proper variable.

Stored Procedure in sql for selecting columns based on input values

I am trying to code a stored procedure in SQL that does the following
Takes 2 inputs (BatchType and "Column Name").
Searches database and gives the batchdate and the data in the column = "Column name"
Code is as give below
ALTER PROCEDURE [dbo].[chartmilldata]
-- Add the parameters for the stored procedure here
(#BatchType nvarchar (50),
#Data nvarchar(50))
AS
BEGIN
-- Insert statements for procedure here
SELECT BatchDate,#Data FROM --Database-- WHERE BatchType = #BatchType
END
I am trying to select column from the database based on operator input. But I am not getting the output. It would be great if someone can give me a direction.
You may want to build out your SELECT statement as a string then execute it using sp_executesql.
See this page for more info:
https://msdn.microsoft.com/en-us/library/ms188001.aspx
This will allow you to set your query to substitute in your column name via your variable and then execute the statement. Be sure to sanitize your inputs though!
You'd need to use dynamic SQL, HOWEVER I would not recommend this solution, I don't think there is anything I can add as to why I wouldn't recommend it that isn't explained better in Erland Sommarskog in The Curse and Blessings of Dynamic SQL.
Nonetheless, if you had to do it in a stored procedure you could use something like:
ALTER PROCEDURE [dbo].[chartmilldata]
-- Add the parameters for the stored procedure here
(#BatchType nvarchar (50),
#Data nvarchar(50))
AS
BEGIN
-- DECLARE AND SET SQL TO EXECUTE
DECLARE #SQL NVARCHAR(MAX) = N'SELECT BatchDate = NULL, ' +
QUOTENAME(#Data) + N' = NULL;';
-- CHECK COLUMN IS VALID IN THE TABLE
IF EXISTS
( SELECT 1
FROM sys.columns
WHERE name = #Data
AND object_id = OBJECT_ID('dbo.YourTable', 'U')
)
BEGIN
SET #SQL = 'SELECT BatchDate, ' + QUOTENAME(#Data) +
' FROM dbo.YourTable WHERE BatchType = #BatchType;';
END
EXECUTE sp_executesql #SQL, N'#BatchType NVARCHAR(50)', #BatchType;
END
It would probably be advisable to change your input parameter #Data to be NVARCHAR(128) (or the alias SYSNAME) though, since this is the maximum for column names.

Resources