I'm trying to send and array of parameters to a stored procedure
SELECT [id_Curso] AS IDCurso
,[Cod_Estabelecimento] AS CodEstabelecimento
,[Des_Estabelecimento] AS DesEstabelecimento
,[Cod_Curso] AS CodCurso
,[Des_Curso] AS DescCurso
,[Cod_Grau] AS CodGrau
,[Des_Grau] AS DescGrau
,[Cod_Area_Educacao] AS CodAreaEducacao
FROM [BEP_DEV].[dbo].[Curso]
where [Cod_Area_Educacao] in #List
DECLARE #List VARCHAR(MAX);
SELECT #List = '(1,2,3,4)';
SELECT [id_Curso] AS IDCurso
,[Cod_Estabelecimento] AS CodEstabelecimento
,[Des_Estabelecimento] AS DesEstabelecimento
,[Cod_Curso] AS CodCurso
,[Des_Curso] AS DescCurso
,[Cod_Grau] AS CodGrau
,[Des_Grau] AS DescGrau
,[Cod_Area_Educacao] AS CodAreaEducacao
FROM [BEP_DEV].[dbo].[Curso]
where [Cod_Area_Educacao] in (1,2,3,4)
How can I transform the first case in something like the 2nd one (which works.)?
I tried also with xml but also can't make it work.
Any help?
There are a number of possibilities for that, but given the you're on SQL 2008 the number one choice would be to use the new table valued parameters, in which you can send a whole table to a query or stored procedure in a single go (in your case, a table with a single column with an arbitrary number of IDs).
First create a table type in your database:
CREATE TYPE idTable AS TABLE (id INT)
Then just declare your procedure with a parameter of that type, and use it like any other table:
CREATE PROCEDURE SelectList (#IDs idTable READONLY) AS
SELECT * FROM sometable
INNER JOIN #IDs AS idTable ON idTable.id=sometable.id
There is a great article that discusses this and other methods in detail for doing what you need http://www.sommarskog.se/arrays-in-sql.html
You can use a udf that parses the string and inserts the values into a table (containing one int column in your case), and then join your Curso table on the table resulting from calling the udf on your CSV string.
I would pass it as xml. Its easy and very performant. Here is a good post with the details. https://www.simple-talk.com/blogs/2012/01/05/using-xml-to-pass-lists-as-parameters-in-sql-server/
Related
Using SQL Server 2012, is it possible to eliminate the need to declare a table-valued parameter (TVP) just to pass it into a stored procedure? Below is a really simple example of a stored procedure (SP) that takes a TVP and a working example to execute that SP where I have to declare the TVP, populate it and then pass it into the SP. I would like to be able to simply pass in the population criteria directly to the EXEC call. Is this possible?
Scenario Setup:
-- Create a sample Users table
CREATE TABLE Users (UserID int, UserName varchar(20))
INSERT INTO Users VALUES (1, 'Bob'), (2, 'Mary'), (3, 'John'), (4, 'Mark')
-- Create a TVP Type
CREATE TYPE UserIdTableType AS TABLE (UserID int)
-- Create SP That Uses TVP Type
CREATE PROCEDURE GetUsers
#UserIdFilter UserIdTableType READONLY
AS
SELECT * FROM #UserIdFilter WHERE UserID > 2
Working Method to Execute:
DECLARE #MyIds AS UserIdTableType
INSERT INTO #MyIds SELECT UserID FROM Users
EXEC GetUsers #MyIds
Requested Method to Execute:
EXEC GetUsers (SELECT UserID FROM Users)
No, you cannot create a TVP inline or CAST / CONVERT it. It is not a "Data Type" like INT, VARCHAR, DATETIME, etc.; it is a "Table Type" which is entirely different. The User-Defined Table Type (UDTT) is just meta-data that is used as the definition/schema for the declaration of a Table Variable. When such a Table Variable is used as an input parameter, that usage is considered a TVP (Table-Valued Parameter). But the thing is still a Table Variable which has its definition stored in tempdb. This is a physical structure, not a memory structure, and you can't CAST or CONVERT a Table, whether it is real, temporary, or a variable.
While the example given in the Question is simplistic for the sake of just getting the idea across, it does seem like your overall goal is code-reuse / creating subroutines (else you could have easily done SELECT * FROM Users WHERE UserID > 2). Unfortunately T-SQL doesn't allow for really elegant / clean code, so you will have to accept a certain level of repetition and/or clunkiness.
It is possible, however, to make slightly generic handlers for result sets, provided they at least have the required fields. You could either
pass in an XML parameter, or
dump the results to a temp table and just refer to it in the sub-proc call (doesn't need to be dynamic SQL) and hence no need to pass in any parameter (at least not one for the dataset / results / query)
In both of those cases, the structure is more flexible than using a TVP since the TVP has to be those exact fields. But referencing a temp table that is assumed to exist allows for something similar to the following:
Proc_1
SELECT *
INTO #MyTemp
FROM sys.tables;
EXEC dbo.Proc_4 #StartsWith = 'a', #HowMany = 10;
Proc_2
SELECT *
INTO #MyTemp
FROM sys.columns;
EXEC dbo.Proc_4 #StartsWith = 'bb', #HowMany = 20;
Proc_3
SELECT *
INTO #MyTemp
FROM sys.views;
EXEC dbo.Proc_4 #StartsWith = 'ccc', #HowMany = 33;
Proc_4
SELECT TOP (#HowMany) tmp.*
FROM #MyTemp tmp
WHERE tmp.[name] LIKE #StartsWith + '%'
ORDER BY tmp.[object_id] ASC;
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
I have a problem when I want to select more then one value in SQL Server. I found a lot of examples with SQL Server Reporting Services but I want to use this stored procedure in a Windows form application.
I have one parameter
#emp nvarchar(50)
select * from table
where crdname = #emp
This one returns table for a single crdname, but I have a situation when I need the table with all crdname.
I have a solution using C# and 2 stored procedures, one procedure for all crdname and one procedure for a single emp, but it's a lot of code for something that I'm missing.
This depends on the scope of the requirements. Do you want it to be one or all? Do you want to be able to do multiple values? For the one or all scenario:
Have a way to pass NULL to the stored procedure then change the WHERE to WHERE (#emp is NULL OR crdname = #emp).
When the parameter is NULL, the WHERE will evaluate to true and you will get all records. When the parameter is not NULL, you will pull the single value you are looking for.
For the multiple values scenario:
Change the = to IN. You might have to create a string split function since you are passing in nvarchar for the parameter.
Use the same stored procedure, but add a condition on the parameter:
CREATE PROCEDURE dbo.YourSP #emp INT = NULL --I assumed the data type
AS
BEGIN
SELECT *
FROM YourTable
WHERE crdname = #emp
OR #emp IS NULL
END;
Then when you want all the results, then call the sp like this:
EXEC dbo.YourSP
And when you want one, then do this:
EXEC dbo.YourSP 1234
You can combine both stored procedures into one, by passing in null for #emp
select *
from table
where #emp is null or crdname = #emp
If #emp is null, then the first condition is true and all rows are returned.
I would suggest two stored procedures, because the above approach is a bit convoluted. But that's just me :)
If you find yourself writing alot of sp's for your winform app, then maybe an ORM would help - e.g. Entity framework?
Is it possible ?
CALL "DBA"."stored_proc"("iParameter" = 'value1','value1','value1','value1','value1')
Or how to make this possible
Parameters must be given a system datatype (except text or image) or a user-defined datatype. I don't think there is a datatype that can hold a list of values.
However, you can use a default parameter that include a wildcard (%) - if the procedure uses the parameter with the like keyword.
For example, you can create a procedure to display information about the system tables if the user does not supply a parameter, like this:
create procedure showind4
#table varchar(30) = "sys%" as
select table_name = sysobjects.name,
index_name = sysindexes.name,
index_id = indid
from sysindexes, sysobjects
where sysobjects.name like #table
and sysobjects.id = sysindexes.id
Alternatively you can pass the suitable parameters for a query that returns this list of values and then create a temporary table (inside the stored procedure) and fill it with the list of values with a select into query. For more on temporary tables in stored procedures see here
In this procedure, I want to delete those number which coming in #msisdn from Master Table and insert into tblDeactive:
ALTER PROCEDURE [dbo].[msisdn_deactivition](#msisdn varchar(1024))
AS
BEGIN
SET NOCOUNT ON;
insert into tblDeactive SELECT * from msisdn_master where msisdn in (#msisdn);
delete from msisdn_master where msisdn in (#msisdn);
END
...but it does not work?
You can't use a single query parameter in place of a list of values. One parameter = one value.
See Parameterize an SQL IN clause for several solutions and lots of discussion about using parameters with the IN( ) predicate.
You need to use a split function, that will split your delimitted #msisdn into a table to select from.
Have a look at this link
How to pass a list of values or array to SQL Server stored procedure?
IN in TSQL needs to take multiple arguments per item. At the moment, if you pass it "123,456,789", it is looking for the single row with value "123,456,789". It isn't looking for "123", "456" or "789".
Look for something like a split udf - plenty on the internet. This takes your delimited string and returns a column of values. Typically you then join the the udf results (rather than use IN).
DON'T use EXEC here, as you shouldn't trust the input.