comma separated value in sql statement from a variable - sql-server-2008-r2

I am getting comma separated value like this in a variable (let say variable name #listobj)
'abc' , 'xyz'
but when I am using below statement it is not giving me the correct result
SELECT * FROM someTable
Where column1 IN (#listobj)
but abc is present in the table.
Where I am doing it wrong?

create a function that split the string to
CREATE FUNCTION dbo.Split(#String varchar(8000), #Delimiter char(1))
returns #temptable TABLE (items varchar(8000))
as
begin
declare #idx int
declare #slice varchar(8000)
select #idx = 1
if len(#String)<1 or #String is null return
while #idx!= 0
begin
set #idx = charindex(#Delimiter,#String)
if #idx!=0
set #slice = left(#String,#idx - 1)
else
set #slice = #String
if(len(#slice)>0)
insert into #temptable(Items) values(#slice)
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end
then make call to the function SELECT * FROM someTable
Where column1 IN (dbo.Split(#listobj))
enter link description here

SQLFiddle demo
select * from someTable
where ','+LTRIM(RTRIM(#listobj))+',' LIKE '%,'+LTRIM(RTRIM(column1))+',%'

A classic question and the answer is no, you cannot use a parameter in this way. There are several workarounds though
One of which is to parse the value inside the stored procedure and dynamically generate sql inside the procedure to be execute later. However, this is not a good practice.
Refer to this question
How to pass a comma separated list to a stored procedure?
and also some good discussion on it here
http://social.msdn.microsoft.com/Forums/en-US/sqlintegrationservices/thread/1ccdd39e-8d58-45b2-9c21-5c4dbd857f95/

Related

IN clause has parameter doesn't work in stored procedure

I have "Name IN (#NameList))" inside of the stored procedure as one of the conditions.
The parameter is declared as #NameList varchar(100) = ''
When I execute the procedure with string like EXEC myProc #NameList='''a'''
the procedure returns nothing, but when I replaced the parameter with hard coded value like 'a' it succeeded.
I put a PRINT statement inside the SP and it prints exactly 'a'
What's wrong here?
Thanks,
Please read my comments as well but one solution would be to split your comma separated string into a table and then join onto that:
declare #list varchar(max) = '13,14,15,13,14,15,13'
SELECT
LTRIM(RTRIM(a.b.value('.[1]','VARCHAR(255)'))) Parish
FROM
(
SELECT CAST('<XMLRoot><RowData>' + REPLACE(#list,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) x)t
CROSS APPLY x.nodes('/XMLRoot/RowData')a(b)

Why does setting a varible like this make a difference?

I have a scalar value function that returns a VarChar(MAX) In my stored procedure I do this
declare #p_emailAddr varchar(MAX) = (select db.dbo.GetEmails(10))
If I do print #p_emailAddr it shows me it was populated with the correct information but the rest of the code doesn't work correctly using it. (I have no clue why, it doesn't make sense!)
Now if I change it like this
declare #p_emailAddr varchar(MAX) = 'test#email.com;'
The rest of my code works perfect as it should!
What is the difference between the two methods of setting #p_emailAddr that is breaking it?
This is get emails code
ALTER FUNCTION [dbo].[GetEmails](#p_SubID int)
RETURNS varchar(max)
AS
BEGIN
DECLARE #p_Emails varchar(max)
SELECT #p_Emails = COALESCE(#p_Emails + ';', '') + E.EmailAddress
FROM db.dbo.UserEmailAddr E JOIN
db.dbo.EmailSubscriptionUsers S on e.ClockNumber = s.Clock AND S.SubID = #p_SubID
SET #p_Emails = #p_Emails + ';'
RETURN #p_Emails
END
What's coming back from GetEmails(10)? varchar(max) is a string value and is expecting a single value. you could have a table variable or if dbo.getemails(10) is a table just join it where you're expecting to use #p_emailaddr
best
select *
from table1 t1
join dbo.GetEmails(10) e
on e.email = t1.email
alternative
create table #GetEmails (emails varchar(max))
insert into #GetEmails values ('email#test.com'), ('test#email.com')
declare #p_emailAddr table (emails varchar(max))
insert into #p_emailAddr(emails)
select *
from #GetEmails
select *
from #p_emailAddr

Conversion failed when converting the nvarchar value 'Internet Explorer 3 original' to data type int

In SQL Server 2008 (TSQL), I've created a stored procedure like this:
CREATE PROCEDURE SP_1_10_2
AS
declare #mostValuableBook nvarchar(255)
SELECT #mostValuableBook = Name
FROM books
WHERE price =
( SELECT MAX(price)
FROM books
WHERE izd LIKE '%BHV%' );
return #mostValuableBook
GO
But, when I'm trying to execute it:
declare #x nvarchar(255)
EXECUTE #x = SP_1_10_2;
SELECT 'The most expensive BHV book:', #x AS 'Name'
GO
I'm getting an error:
Conversion failed when converting the nvarchar value 'Internet
Explorer 3 original' to data type int.
It seems like the problem is in the line
EXECUTE #x = SP_1_10_2;
Can you please tell me what's wrong? Why is it trying to convert to int?
RETURN cannot be used to return nvarchar / varchar such as you have. RETURN is used to return an integer, this can be expressed as some sort of status code 1=True / 0=False. Read more about return here: http://msdn.microsoft.com/en-us/library/ms174998.aspx
In your case, you simply need to use OUTPUT variables which is similiar to pass-by-ref in C# or C++. You pass the variable to the sproc, the sproc modifies it, and you get the expected results after a SELECT....
Change it so that your parameters becomes an output parameter:
CREATE PROCEDURE SP_1_10_2
#mostValueableBook nvarchar(255) output
AS
SELECT #mostValuableBook = Name
FROM books
WHERE price =
( SELECT MAX(price)
FROM books
WHERE izd LIKE '%BHV%' );
SELECT #mostValuableBook
GO
Call it like so:
DECLARE #theValBook nvarchar(255)
EXECUTE SP_1_10_2 #mostValuableBook = #theValBook output
Then you can say:
SELECT 'Most expensive book is', #theValBook
You can also create a function to return the value you desire instead of relying on numeric return codes. SQL Functions come in quite handy. See example below which returns the last name with the highest client id using the LIKE operator
Use MYDB
GO
CREATE Function fn_LastClientIdByName
(
#nameLike NVARCHAR(10)
)
RETURNS NVARCHAR(100)
AS
BEGIN
DECLARE #result nvarchar(100)
DECLARE #clientName NVARCHAR(100)
SELECT top 1 #clientName = [clientLast] + ' ' + [clientFirst]
FROM [dbo].[duiClientOnly]
WHERE clientLast like #nameLike + '%'
order by clid desc
select #result = #clientName
return #result
END

TSQL: Determine number of columns returned by Stored Procedure

This probably has been asked before, but I was unable to find a satisfying answer.
I need to insert results of a stored procedure into a temporary table, something like:
INSERT INTO #TEMP EXEC MY_SP
I don't know in advance how many columns the SP will return, so I need to prepare my #TEMP table (via dynamic ALTER .. ADD commands) to add columns to match SP resultset.
Assumption is - SP accepts no parameters and number of columns is always the same. But how do I determine that number in pure TSQL outside of SP so I can store it for example into a variable?
Tough one, especially if someone else is denying you the necessary permissions to run e.g. OPENROWSET.
Have you considered unpacking/script the SP and add its contents directly to your T-SQL? In this way you can modify and adapt it however you may want.
Otherwise, if you could explain more about the SP:
What does the SP do?
What kind of information does it output? One-N columns, - how many rows?
Is it slow/fast? (Could we perhaps use a brute-force [try-catch] approach)?
How does it determine the columns to output and how often does that change?
Can you pre-determine the columns in any way? (So that you may use an INSERT #temp EXEC sp_getData syntax).
Best of luck!
It's a bit awkward, but you can do something like:
SELECT * INTO #temp
FROM OPENROWSET('SQLOLEDB','Data Source=MyServer;Trusted_Connection=yes;Integrated Security=SSPI', 'EXECUTE MyDB.MySchema.MyProcedure #MyParm=123')
I've requested an EXECUTE INTO syntax, like SELECT INTO to avoid having to know the shape of the stored proc output in advance, but it was rejected
Let me say from the start that if I had to do this I would try find a way to do it outside the SQL environment or something else, because the solution I am providing is not a good way to do this, but it works. So I am not saying that this is a good idea.
I have a sp called test:
CREATE PROCEDURE Test
AS
SELECT 1 as One, 2 as Two
To execute this dynamically I do the following:
DECLARE #i int
SET #i = 1;
DECLARE #SUCESS bit
SET #SUCESS = 0
WHILE(#SUCESS = 0)
BEGIN
DECLARE #proc VARCHAR(MAX)
DECLARE #count int
SET #count = 1
SET #proc = 'DECLARE #t TABLE ( c1 varchar(max) '
WHILE #count < #i
BEGIN
SET #proc = #proc + ', c' + CONVERT(varchar, #count + 1) + ' varchar(max) '
print #proc
SET #count = #count + 1
END
SET #proc = #proc + '); INSERT INTO #t EXEC Test'
BEGIN TRY
EXEC(#proc);
SET #SUCESS = 1
END TRY
BEGIN CATCH
SET #i = #i+1
END CATCH
END
SET #proc = #proc + '; SELECT * into ##t FROM #t '
EXEC( #proc )
SELECT * from ##t
This is a poor solution to your problem because you have lost the data type of your columns, their names etc.
I don't understand the syntax, and this probably isn't the best way, but someone seems to have done this with converting to xml and parsing it: Dynamic query results into a temp table or table variable

Array-like access to variables in T-SQL

In my stored procedure I have multiple similar variables #V1, #V2 ... #V20 (let's say 20 of them) FETCHED from a record. How would I use dynamic SQL to make 20 calls to another stored procedure using those variables as parameters?
Of course #V[i] syntax is incorrect, but it expresses the intent
fetch next from maincursor into #status, #V1, #V2, ...
while #i<21
begin
-- ??? execute sp_executesql 'SecondSP', '#myParam int', #myParam=#V[i]
-- or
-- ??? execute SecondSP #V[i]
set #i = #i+1
end
As others have said, set up a temporary table, insert the values that you need into it. Then "iterate" through it executing the necessary SQL from those values. This will allow you to have 0 to MANY values to be executed, so you don't have to set up a variable for each.
The following is a complete sample of how you may go about doing that without cursors.
SET NOCOUNT ON
DECLARE #dict TABLE (
id INT IDENTITY(1,1), -- a unique identity column for reference later
value VARCHAR(50), -- your parameter value to be passed into the procedure
executed BIT -- BIT to mark a record as being executed later
)
-- INSERT YOUR VALUES INTO #dict HERE
-- Set executed to 0 (so that the execution process will pick it up later)
-- This may be a SELECT statement into another table in your database to load the values into #dict
INSERT #dict
SELECT 'V1Value', 0 UNION ALL
SELECT 'V2Value', 0
DECLARE #currentid INT
DECLARE #currentvalue VARCHAR(50)
WHILE EXISTS(SELECT * FROM #dict WHERE executed = 0)
BEGIN
-- Get the next record to execute
SELECT
TOP 1 #currentid = id
FROM #dict
WHERE executed = 0
-- Get the parameter value
SELECT #currentvalue = value
FROM #dict
WHERE id = #currentid
-- EXECUTE THE SQL HERE
--sp_executesql 'SecondSP', '#myParam int', #myParam =
PRINT 'SecondSP ' + '#myParam int ' + '#myParam = ' + #currentvalue
-- Mark record as having been executed
UPDATE d
SET executed = 1
FROM #dict d
WHERE id = #currentid
END
Use a #TempTable
if you are at SQL Server 2005 you can create a #TempTable in the parent stored procedure, and it is available in the child stored procedure that it calls.
CREATE TABLE #TempTable
(col1 datatype
,col2 datatype
,col3 datatype
)
INSERT INTO #TempTable
(col1, col2, col3)
SELECT
col1, col2, col3
FROM ...
EXEC #ReturnCode=YourOtherProcedure
within the other procedure, you have access to #TempTable to select, delete, etc...
make that child procedure work on a set of data not on one element at a time
remember, in SQL, loops suck performance away!
Why not just use the table variable instead, and then just loop through the table getting each value.
Basically treat each row in a table as your array cell, with a table that has one column.
Just a thought. :)
This seems like an odd request - will you always have a fixed set of variables? What if the number changes from 20 to 21, and so on, are you constantly going to have to be declaring new variables?
Is it possible, instead of retrieving the values into separate variables, to return them each as individual rows and just loop through them in a cursor?
If not, and you have to use the individual variables as explained, here's one solution:
declare #V1 nvarchar(100)
set #V1 = 'hi'
declare #V2 nvarchar(100)
set #V2 = 'bye'
declare #V3 nvarchar(100)
set #V3 = 'test3'
declare #V4 nvarchar(100)
set #V4 = 'test4'
declare #V5 nvarchar(100)
set #V5 = 'end'
declare aCursor cursor for
select #V1
union select #V2 union select #V3
union select #V4 union select #V5
open aCursor
declare #V nvarchar(100)
fetch next from aCursor into #V
while ##FETCH_STATUS = 0
begin
exec TestParam #V
fetch next from aCursor into #V
end
close aCursor
deallocate aCursor
I don't really like this solution, it seems messy and unscalable. Also, as a side note - the way you phrased your question seems to be asking if there are arrays in T-SQL. By default there aren't, although a quick search on google can point you in the direction of workarounds for this if you absolutely need them.