Stored procedure Not Accepting Newline character in parameter - sql-server

I am trying to put comma separated values as parameter to stored procedure, but when I am pressing "Enter" key for continuing the values so that it can be seen in single screen (without scrolling) , SP is not accepting the values which are provided after "Enter" key is pressed(means in new line)
USP_SAMPLE_SP #YEAR, #EMPIDS
If I am executing stored procedure as below :
USP_SAMPLE_SP '2016','111,222,333,444,555'
It is executing properly
But if I am trying to execute like below :
USP_SAMPLE_SP '2016','111,222,
333,444,555'
It is accepting all values however it is showing values up to '222' after that it is not considering any value.
Referring to "Newline" I mean is it is accepting like below :
USP_SAMPLE_SP '2016','111, 222,333,444,555'
But if I am pressing "Enter" it is not accepting values after that
If any one can explain this scenario it will be helpful.
Note: Sometimes I need to pass large number of values(ex. 1000 or above).
Please suggest if any one knows better and efficient way to do this.
First I am creating User-Defined Table Type as EMPType
CREATE TYPE [dbo].[EMPType] AS TABLE(
FinStartYear varchar(4),
EmpId nvarchar(max) NULL
)
Then I am trying to pass those values for altering my stored procedure as below :
ALTER PROCEDURE [USP_SAMPLE_SP]
-- Add the parameters for the stored procedure here
#FinStartYear EMPType readonly ,
#EmpIDs EMPType readonly
AS
But when I hover mouse over the parameter it shows me below error :
The Parameter '#FinStartYear' cannot be declared READONLY since it is not table valued parameter.
The Parameter '#EmpIDs' cannot be declared READONLY since it is not table valued parameter.
But when I am trying to alter the stored procedure it is showing me below error :
Must declare the scalar variable "#EmpIDs".
Must declare the scalar variable "#FinStartYear"
When I hover over 'EMPType' it shows me below error :
Parameter or variable '#FinStartYear' has an invalid datatype.
NOTE : Under Programmability -> Types -> User-Defined Table Types ->dbo.EMPType
It is showing me EMPType has been created.

It's not possible to be certain without seeing the code of your stored procedure, but I suspect that the newline character somehow breaks the code which is used to split the delimited string into a result set; the newline character is interpreted as a terminator and all the values following it are ignored.
There are several possible solutions.
One is to build your list of input values from a series of shorter strings, enabling you to control how the list appears on the screen without affecting its content. Note that this requires the use of a variable:
-- I am guessing the data type of the #EMPIDS parameter. Use a matching type for #IDS
DECLARE #IDS VARCHAR(MAX) = '111,222,'
+ '333,444,555'
EXEC USP_SAMPLE_SP #YEAR = '2016', #EMPIDS = #IDS
Another would be to amend the code of the stored procedure to strip out newline characters before splitting the delimited list. I wouldn't recommend this, since this behaviour might be relied on by other users of the code.
Edit
Here's an example of how to replace newline characters:
DECLARE #EMPID varchar(100) = '111,222,
333,444,555'
SET #EMPID = REPLACE(REPLACE(#EMPID,CHAR(13),''),CHAR(10),'')
SELECT #EMPID
Before you use this, make sure you're not going to affect any other users of this code who might rely on the current behaviour.
Another solution would be to amend the stored procedure to accept a table-valued parameter rather than a delimited list. This is a little more complex to set up but likely to perform than better than splitting a delimited string, especially if the string contains thousands of values.
Edit 2
I think you might have misunderstood how a table-valued parameter works. It enables you to completely avoid the concatenated list of EMPIDs, and instead work with a table variable containing one EMPID per row which can be passed as an argument to a stored procedure.
Here's a worked example:
CREATE TYPE dbo.EMPType AS TABLE(
EmpId int NOT NULL PRIMARY KEY
)
GO
-- I don't know what your procedure does so I've created a simple stub
-- which shows how to use the table-valued parameter like a table
CREATE PROCEDURE dbo.USP_SAMPLE_SP
#FinStartYear varchar(4),
#empids EMPType readonly
AS
SELECT #FinStartYear AS out_year, EmpId
FROM #empids
ORDER BY EmpId
GO
-- use the code from here to the end of the example every time
-- you want to execute the procedure (setting the list of EMPID values appropriately
DECLARE #in_emp EMPType --declare an instance of EMPType as a variable
INSERT #in_emp(EmpId) VALUES (111),(333),(222),(555),(444) --insert some values into the variable
EXEC dbo.USP_SAMPLE_SP #FinStartYear = '2016',#empids = #in_emp --pass the variable as a parameter to the stored procedure
GO

Related

Multi-value parameters in stored procedure return errors when multiple values are passed to them

I'm creating a stored procedure that uses two multi-value parameters:
#Class AS VARCHAR(5),
#Service AS VARCHAR(5)
(…)
WHERE B.UTRCLS IN (#Class) AND B.UTSVC IN (#Service)
The procedure works fine when both parameters only contain one value. However, when either or both use multiple values, it throws an error.
In report builder the error is the following:
Cannot read the next data row for the dataset DataSet1 (rsErrorReadingNextDataRow)
In SQL Server, the error appears as the following (truncated for length):
Cannot execute the query "SELECT
Col1009,Col1010,Col1008,Expr1003,Expr1004 FROM (SELECT
Col1009,Tbl1001.UTCSNM Col1008,Col1010,SUM(Col1016)
Expr1003,SUM(Col1014) Expr1004 FROM (…)
I don't think I'm doing anything wrong with declaring the parameters. Is this an issue with multi-value parameters in stored procedures?
You need to use a dynamic query:
SET #sqlCommand = 'SELECT * FROM yourTable B WHERE B.UTRCLS IN ( +' #Class + ')' +
' AND B.UTSVC IN (' + #Service +' )'
EXECUTE sp_executesql #sqlCommand
The comments on your post are on the right track. Parameters are single valued for the scope of the stored procedure call, not iterated through for sets of parameter values. I think you have 2 options if you want to pass many values into those parameters.
The first is to expand the character length of your parameters and incorporate a delimiter to segment the values. Your stored procedure code would then need to parse these values and do what is needed from there for each. The STRING_SPLIT() function would help you along the way.
The second options is to define a user data type of type table that mirrors the data structure of the multi-values you need to pass in the parameter. In your stored procedure call you would define a variable of this type, fill it with the values and then pass that variable to your stored procedure. Note that these must be set to READ ONLY when doing so.
Link to MSDN for creating user types: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-type-transact-sql?view=sql-server-2017

Stored procedure Inserts Hebrew characters into an NVARCHAR column, but SELECT shows "?"

When I SELECT from the table, the data that I stored is stored as question marks.
#word is a parameter in my stored procedure, and the value comes from the C# code:
string word = this.Request.Form["word"].ToString();
cmd.Parameters.Add("#word", System.Data.SqlDbType.NVarChar).Value = word;
My stored procedure is like this:
CREATE PROCEDURE ....
(
#word nvarchar(500)
...
)
Insert into rub_translate (language_id,name)
values (8 ,#word COLLATE HEBREW_CI_AS )
My database, and the column, is using the SQL_Latin1_General_CP1_CI_AS collation and I cannot change them.
Can anybody give me a solution how can I solve this problem just by modifying the column or the table?
In order for this to work you need to do the following:
Declare the input parameter in the app code as NVARCHAR (you have done this)
Declare the input parameter in the stored procedure as NVARCHAR (no code is shown for this)
Insert or Update a column in a table that is defined as NVARCHAR (you claim that this is the case)
When using NVARCHAR it does not matter what the default Collation of the Database is. And actually, when using NVARCHAR, it won't matter what the Collation of the column in the table is, at least not for properly inserting the characters.
Also, specifying the COLLATE keyword in the INSERT statement is unnecessary and wouldn't help anyway. If you have the stored procedure input parameter defined as VARCHAR, then the characters are already converted to ? upon coming into the stored procedure. And if the column is actually defined as VARCHAR (you haven't provided the table's DDL) then if the Collation isn't Hebrew_* then there is nothing you can do (besides change either the datatype to NVARCHAR or the Collation to a Hebrew_ one).
If those three items listed at the top are definitely in place, then the last thing to check is the input value itself. Since this is a web app, it is possible that the encoding of the page itself is not set correctly. You need to set a break point just at the cmd.Parameters.Add("#word", System.Data.SqlDbType.NVarChar).Value = word; line and confirm that the value held in the word variable contains Hebrew characters instead of ?s.
ALSO: you should never create a string parameter without specifying the max length/size. The default is 30 (in this case, sometimes it's 1), yet the parameter in the stored procedure is defined as NVARCHAR(500). This could result in silent truncation ("silent" meaning that it will not cause an error, it will just truncate the value). Instead, you should always specify the size. For example:
cmd.Parameters.Add("#word", System.Data.SqlDbType.NVarChar, 500).Value = word;
You could just insert it as-is, since it's unicode and then select it with a proper collation:
declare #test table([name] nvarchar(500) collate Latin1_General_CI_AS);
declare #word nvarchar(500) = N'זה טקסט.';
insert into #test ( [name] ) values ( #word );
select [t].[name] collate Hebrew_CI_AS from #test as [t]
Or you can change the collation of that one column in the table all together. But remember that there is a drawback of having a different collation from your database in one or more columns: you will need to add the collate statement to queries when you need to compare data between different collations.

SQL Server: ltrim on User-Defined Table Types

I have a SQL Server 2012 User-Defined Table Types that I am using to get data from a PHP array and pass that data to a Procedure. Sometimes I get white spaces from the web app and I would like to use ltrim/rtrim to clean it. Can I do this at the User-Defined Table Type level? IE: where I declare that it should expect a parm1 varchar(10) can I somehow trim is there? I haven't had any luck. Thank you
Example, my Table Type looks like this:
CREATE TYPE LocationTableType AS TABLE
( LocationName VARCHAR(50)
, CostRate INT );
GO
I want to change it so that when LocationName comes in, it will ltrim()/rtrim() to clear out any extra spaces.
I assume that reported issue is linked to READONLY property of table valued params, property that is mandatory. This means that rows from table valued params can not be updated/deleted and also we can't insert other rows.
CREATE PROCEDURE dbo.DoSomething
#list dbo.LocationTableType READONLY -- <-- table table param have to be READONLY
AS
BEGIN
SELECT * FROM #list
END
On short term solution could be
1)to declare another variable within stored procedure
2)insert trimmed data into this variable and then
3)to change next references to all variable - param to new variable.
ALTER PROCEDURE dbo.DoSomething
#list dbo.LocationTableType READONLY
AS
BEGIN
DECLARE #listNoSpc dbo.LocationTableType -- New variable
INSERT #listNoSpc (LocationName, CostRate) -- Inserting trimmed data
SELECT LTRIM(l.LocationName), l.CostRate
FROM #list l
SELECT * FROM #listNoSpc -- Update references from #list to #listNoSpc
END
GO
Permanent solution should be to update webapp (PHP) to remove those spaces before sending data to SQL Server.

SQL stored procedure get dynamic parameter list with values

I have an interesting scenario where I need to get a dynamic list of parameter values from inside a stored procedure. I want a generic t-sql script that will return this information to me without having to type out each parameter name.
The reason for this is that before executing multiple stored procedures, I must first pass the list of parameter values into another stored procedure call. I don't want the tedious maintenance task that whenever a parameter is added/changed in the SP, I will have to change the nested call as well.
Ex:
create procedure sp1 #a int = 1, #b int = 2
as begin
exec sp2 '1, 2'
....
end
Adding another parameter #c int, should automatically get added on to the string passed in to sp2.
I know I can retrieve the parameter names from sys.parameters using object_id = ##procid. I can concatenate them using for xml path. However, I would need to then use sp_executesql to retreive the values - which would require me to specify each parameter name. Hence, I am no better off than before.
Any tips or help would be greatly appreciated.
Thank you.

Passing multiple value parameters in SSRS to stored procedure

I am trying to pass a multiple value string parameter to a table type parameter in a SQL Server 2012 stored procedure. I paste this code in the dataset of SSRS:
DECLARE #mylist clinic_list_tbltype
INSERT #mylist(n) VALUES (#pm_ChooseClinics)
EXEC sp_Skillset_Summary_With_Callbacks_Report #mylist, #pm_ChooseInterval, #pm_StartDateTime, #pm_EndDateTime
clinic_list_tbltype is a table type I created with one varchar(50) field named "n". I can call this stored procedure from SSMS o.k. like this (and it comes back very fast):
DECLARE #mylist clinic_list_tbltype
INSERT #mylist(n) VALUES ('clinicA'), ('clinicB')
EXEC sp_Skillset_Summary_With_Callbacks_Report #mylist, 'Daily', '6/3/2014', '6/9/2014'
I can run in SSRS for only one clinic (but very slow), but if I try more than one it gives an error saying that
there are fewer columns in the INSERT statement than values specified
in the Values clause
. Even running for one clnic it works, but it takes a very very long time compared to running the query in SSMS. Like 2 minutes vs. 1 second. Must be because I'm passing ('clinicA', 'clinicB') instead of ('clinicA'), ('clinicB').
How to do?
Right I need to give you some back ground 1st.
When you allow SSRS parameter to select multiple values, The selection of multiple values creates a comma deliminated string of value as one string
'value1,value2,value3'
To check values in a string using IN operator we need strings concatenated with commas something like this ....
'value1','value2','value3'
Your Proc
Now in your proc when you insert values explicitly it inserts multiple values into your table.
INSERT INTO Table_Value_Param
VALUES ('value1'), --<-- 1st value/Row
('value2'), --<-- 2nd Value/Row
('value3') --<-- 3rd Value/Row
and this gives you back the expected results as when inside your procedure you execute a statement like
SELECT *
FROM Table_Name
WHERE ColumnName IN (SELECT ColumnName
FROM Table_Value_Param)
On the other hand when you try to insert into table using SSRS report Parameter you table inserts value like
INSERT INTO Table_Value_Param
VALUES ('value1,value2,value3') --<-- One Row/Value containing all the values comma separated
Solution
Creating TVP in this situation doesnt really help, What I do is make use of dbo.Split() function inside my procedure.
You can find many definitions for split function online, for a some cool ones have a look here Split Function equivalent in tsql?
Once you have created this split function just use this function inside your procedure definition you dont even need the Table valued parameters then.
Something like this...
SELECT *
FROM Table_Name
WHERE ColumnName IN (
SELECT Value
FROM dbo.Split(#Report_Param, ',')
)
declare #Vendors_Filter nvarchar(max) = 'a,b,c'
declare #Vendors nvarchar(max)
set #Vendors =''''+replace(#Vendors_Filter,',',''',''')+''''
select #Vendors

Resources