Create IN subquery from a VARCHAR parameter with comma separated values [duplicate] - sql-server

This question already has answers here:
T-SQL stored procedure that accepts multiple Id values
(5 answers)
Closed 8 years ago.
I have a stored procedure that I need to pass a comma-delimited variable to.
For example, if a certain condition exists, I would pass a list of country codes like this:
AU,RA,PK
The number of items can vary.
In the stored procedure, I need to use those items in an IN clause such as follows:
WHERE CountryCode IN (#ExcludeCountries)
Is there any way to do this? I can massage the country codes going in to something like N'AU', N'RA', N'PK' if need be.
Thanks.

WHERE CountryCode IN (SELECT *
FROM [dbo].[ufn_CSVToTable](#ExcludeCountries,',')
This is how you can create [dbo].[ufn_CSVToTable]:
How to convert comma separated NVARCHAR to table records in SQL Server 2005?

In practice I've seen this problem resolved using the function below. This function splits the string and return a table containing the values specified. Then use it like this...
...CountryCode IN (SELECT * FROM dbo.SplitString(#ExcludeCountries ,','))
Notice that in this example the comma (',') is the delimiter. I've used this method for years and I haven't encounter any performance problems.
CREATE FUNCTION [dbo].[SplitString]
(
#SplitStr nvarchar(MAX),
#SplitChar nvarchar(5)
)
RETURNS #RtnValue table
(
Data nvarchar(MAX)
)
AS
BEGIN
Declare #Count int
Set #Count = 1
While (Charindex(#SplitChar,#SplitStr)>0)
Begin
Insert Into #RtnValue (Data)
Select
Data = ltrim(rtrim(Substring(#SplitStr,1,Charindex(#SplitChar,#SplitStr)-1)))
Set #SplitStr = Substring(#SplitStr,Charindex(#SplitChar,#SplitStr)+1,len(#SplitStr))
Set #Count = #Count + 1
End
Insert Into #RtnValue (Data)
Select Data = ltrim(rtrim(#SplitStr))
Return
END

There are two ways to do that:
Using the #ExcludeCountries parameter build table variable table that is latter join to your query
Build a dynamic SQL statement like this
... + 'WHERE CountryCode IN' (' + #ExcludeCountries + ')' ...
and then use sp_executesql to exec the statement

Related

Conditional IN clause in SQL Server [duplicate]

This question already has answers here:
T-SQL stored procedure that accepts multiple Id values
(5 answers)
Closed 4 years ago.
I have got a stored procedure which has five parameters. I want to include them in where clause as follows
If parameter is not null then include it in query as an IN clause
That is, parameter value can be like 'Test' or 'Test,Best' etc. I'm converting this comma seperated values into table using function in SQL.
I tried to use COALESCE(#test,test_column) = test_column but i'm unable to include IN clause here (What if #test = 'Test,Best').
So, i want to do something like mentioned below
DECLARE #param varchar(max) = 'Test,Best';
Select * from table where CASE when #param is not null then table.column in (#param)
Any suggestions please.
I've adapted this answer to your requirements.
First create User-Defined Table type:
CREATE TYPE dbo.ParamsList
AS TABLE
(
Param varchar(50)
);
Then just use this parameter and other parameters in your stored procedures:
CREATE PROCEDURE dbo.DoSomethingWithEmployees
#List AS dbo.ParamsList READONLY
, #param1 INT = NULL
, #param2 NVARCHAR(150) = NULL
, #param3 NVARCHAR(150) = NULL
, #param4 NVARCHAR(150) = NULL
AS
BEGIN
SET NOCOUNT ON;
SELECT
*
FROM YourTable
WHERE YourColumn NOT IN (SELECT Param FROM #List)
END
GO

When exactly do we use stored procedures with output parameters?

When exactly do we use stored procedures with output parameters and when do we use stored procedures without parameters?
I base my question on an example:
Stored procedure with output parameter
CREATE PROCEDURE uspGetContactsCountByCity
#City nvarchar(60),
#ContactsCount int OUT
AS
BEGIN
SELECT #ContactsCount = COUNT(ContactID)
FROM Contacts
WHERE City = #City
END
Stored procedure executing
DECLARE #ContactsTotal INT
EXEC uspGetContactsCountByCity #ContactsCount = #ContactsTotal OUT, #city = 'Berlin'
SELECT #ContactsTotal
Results: 2
Stored procedure without output parameter
CREATE PROCEDURE uspGetContactsCountByCity2
#City nvarchar(60)
AS
BEGIN
SELECT COUNT(ContactID)
FROM Contacts
WHERE City = #City
END
Stored procedure executing:
EXEC uspGetContactsCountByCity2 #city = 'Berlin'
Results: 2
Both procedures return the same result, in same form, so what's the difference?
Basically, the result you're seeing is actually the result of your SELECT at the end of the procedure, which is doing the same thing.
Please take a look at this documentation:
If you specify the OUTPUT keyword for a parameter in the procedure definition, the stored procedure can return the current value of the parameter to the calling program when the stored procedure exits. To save the value of the parameter in a variable that can be used in the calling program, the calling program must use the OUTPUT keyword when executing the stored procedure.
So basically if you would like your stored procedure to just return just a value instead of a data set, you could use the output parameter. For example, let's take the procedures you have given as an example. They both do the same thing, this is why you got the same result. But what about changing a little bit in the first procedure that has the output parameter.
Here's an example:
create table OutputParameter (
ParaName varchar(100)
)
insert into OutputParameter values ('one'), ('two'),('three'),('one')
CREATE PROCEDURE AllDataAndCountWhereOne
#name nvarchar(60),
#count int OUT
as
Begin
SELECT #count = COUNT(*) from OutputParameter
Where ParaName = #name
select Distinct(ParaName) from OutputParameter
End
Declare #TotalCount int
Exec AllDataAndCountWhereOne #count = #TotalCount OUT, #name = 'One'
Select #TotalCount
With this example, you are getting all the distinct stored data in the table, plus getting the count of a given name.
ParaName
--------------------
one
three
two
(3 row(s) affected)
-----------
2
(1 row(s) affected)
This is one way of using the output parameter. You got both the distinct data and the count you wanted without doing extra query after getting the initial data set.
At the end, to answer your question:
Both procedures gives us the same result, in same form, so what's the difference?
You didn't make a difference in your own results, this is why you didn't really notice the difference.
Other Examples:
You could use the OUT parameter in other kinds of procedures. Let's assume that your stored procedure doesn't return anything, it's more like a command to the DB, but you still want a kind of message back, or more specifically a value. Take these two examples:
CREATE PROCEDURE InsertDbAndGetLastInsertedId
--This procedure will insert your name in the database, and return as output parameter the last inserted ID.
#name nvarchar(60),
#LastId int OUT
as
Begin
insert into OutputParameterWithId values (#name);
SELECT #LastId = SCOPE_IDENTITY()
End
or:
CREATE PROCEDURE InsertIntoDbUnlessSomeLogicFails
--This procedure will only insert into the db if name does exist, but there's no more than 5 of it
#name nvarchar(60),
#ErrorMessage varchar(100) OUT
as
Begin
set #ErrorMessage = ''
if ((select count(*) from OutputParameterWithId) = 0)
begin
set #ErrorMessage = 'Name Does Not Exist'
return
end
if ((select count(*) from OutputParameterWithId) = 5)
begin
set #ErrorMessage = 'Already have five'
return
end
insert into OutputParameterWithId values (#name);
End
These are just dummy examples, but just to make the idea more clear.
An example, based on yours would be if you introduced paging to the query.
So the result set is constrained to 10 items, and you use a total count out parameter to drive paging on a grid on screen.
Answer from ozz regarding paging does not make sense because there is no input param that implements a contraint on the number of records returned.
However, to answer the question... the results returned by these stored procedures are not the same. The first returns the record count of contacts in given city in the out param ContactsCount. While the count may also be recieved in the second implement through examining the reader.Rows.Count, the actual records are also made a available. In the first, no records are returned - only the count.

How to pass more than one char as a variable in a stored procedure?

I've created the following stored procedure:
ALTER PROCEDURE [dbo].[CountInJunction]
#Mod as nvarchar(10),
#Junction as nvarchar(10),
#PJ as nvarchar(10),
**#case as varchar(10)**,
#Date as varchar(20)
as
begin
declare #result as int
select #result = count(distinct CONCAT ([UCID],[CALLSEGMENT]))
from IVR_LINES
where MODULE = #Mod and DATE = #date
and EVENT_NAME = #Junction and **EVENT_VALUE in (#case)**
insert into [dbo].[MainJuncTable] values(#Mod,#PJ,#Junction,#case,#result,null,null,#date)
return #result
end
I would like to pass ('0','5') as #case.
for some reason, I get 0 as a result, which is not correct. Its seems that the SP doesn't interpret ('0','5') correctly.
I've been trying multiple combinations such as:
'0','5'
'0'+','+5''
'0,5'
etc..
nothing works.
Is there any way I can pass these chars correctly?
Thanks.
Send the values as a single string like ('0,5')
Then in where condition u need to split and select the values like,
where EVENT_VALUE in (select val from Split(#case,','))
Split is user defined function,you need to create before using it.
CREATE FUNCTION [dbo].[Split]
(
#delimited nvarchar(max),
#delimiter nvarchar(100)
) RETURNS #t TABLE
(
-- Id column can be commented out, not required for sql splitting string
id int identity(1,1), -- I use this column for numbering splitted parts
val nvarchar(max)
)
AS
BEGIN
declare #xml xml
set #xml = N'<root><r>' + replace(#delimited,#delimiter,'</r><r>') + '</r></root>'
insert into #t(val)
select
r.value('.','varchar(max)') as item
from #xml.nodes('//root/r') as records(r)
RETURN
END
GO
In every case, use this as your parameter value: '0,5'
But how to use it depends on the version of sql server you're using.
If you've got 2016, there's STRING_SPLIT. https://msdn.microsoft.com/en-us/library/mt684588.aspx
If you don't have it, you can create a function. See related stackoverflow posts: How to split a comma-separated value to columns
Or if you want rows: SQL query to split column data into rows
(See the higher rated recommendations in both of those.)

how to pass an int-set to sqlserver in a string to stored procedure and use it in an IN-Clause

I need to call a stored procedure like this:
exec myProcedure '(5, 15, 45)'
And inside the procedure I need to use the int-set within an in-Clasue
like this:
SELECT ... FROM table WHERE (days in #intSet)
This always bring a syntax Error in the WHERE-Clause.
(SqlServer evidently does not allow to simply replace a part of the statement by a string)
I plan a solution like this:
I can easily split the integer values of the string into several integers using
CHARINDEX, SUBSTRING, RTRIM, LTRIM, CONVERT - this is not an issue - it works fine.
But I still cannot figure out into what kind of variable could I then put those integers in order to later use it with the IN-Clause ?
any ideas are greatly appreciated
Gerald
You will need to create a split function inside you database,
Definition Of Split Function
CREATE FUNCTION [dbo].[split]
(
#delimited NVARCHAR(MAX),
#delimiter NVARCHAR(100)
)
RETURNS #t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
AS
BEGIN
DECLARE #xml XML
SET #xml = N'<t>' + REPLACE(#delimited,#delimiter,'</t><t>') + '</t>'
INSERT INTO #t(val)
SELECT r.value('.','varchar(MAX)') as item
FROM #xml.nodes('/t') as records(r)
RETURN
END
Stored Procedure
Then you would use this split function insdie your Procedure to split the values to be used with In operator.
CREATE PROCEDURE GetData
#intSet VARCHAR(1000) = NULL
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM TableName
WHERE days IN (SELECT Val FROM dbo.split(#intSet ))
END

Stored Procedure.. using sql server

Can any tell me how to send the LIst of IDs to the stored procedure in sql.
I need to send the List from My Controller so that that List of ID's can execute at a time using stored procedure.
Thanks
In SQL Server 2008 and up you can use Table-Valued Parameters
The best way (in 2008) is to pass it as a table. Pre 2008 you had to use a CSV format VarChar then split it out.
Have a read of this: http://www.sommarskog.se/arrays-in-sql-2008.html
What about a comma delimited string of Id's?
The problem is sql server doesn't support an array data type (or similar)
Sounds like you need something along the lines of this:
CREATE FUNCTION [dbo].[Split_String]
(
#ConcatValues VARCHAR(MAX)
)
RETURNS #Values Table
(
Value VARCHAR(MAX)
)
AS
/**************************************************************************************************************
Purpose: When called from a stored procedure and passed a character delimited parameter (of String data type values),
this function returns a table named "#Values" with a field named "Value" (populated with the parameter list)
which can then be referenced in the stored procedure.
This function requires that the delimited paramater have as its first character the delimiter character.
Sample calls:
Select * from [dbo].[Split_String](';dog;cat;mouse')
Select * from [dbo].[Split_String]('| dog| cat| mouse|')
Select * from [dbo].[Split_String]('|')
Select * from [dbo].[Split_String]('')
**************************************************************************************************************/
BEGIN
--Indexes to keep the position of searching
DECLARE #Delim CHAR(1)
Declare #Pos1 Int
Declare #Pos2 Int
--Identify delimiter character
SET #Delim = SUBSTRING(#ConcatValues, 1, 1)
--Append delimiter character
Set #ConcatValues = #ConcatValues + ' ' + #Delim
--Set 1st character of 1st value
Set #Pos2 = 2
While #Pos2 < Len(#ConcatValues)
BEGIN
Set #Pos1 = CharIndex(#Delim, #ConcatValues, #Pos2)
Insert #Values SELECT LTRIM(RTRIM(Substring(#ConcatValues, #Pos2, #Pos1 - #Pos2)))
--Go to next non-delimiter character
Set #Pos2 = #Pos1 + 1
END
RETURN
END
GO
Our split function is generic for use in a wide variety of situations and is dependent on the delimiter being identified by the first character in the string. It is likely that it could be simplified a bit if you only need it in one spot.

Resources