How to pass an array into a SQL Server stored procedure?
For example, I have a list of employees. I want to use this list as a table and join it with another table. But the list of employees should be passed as parameter from C#.
SQL Server 2016 (or newer)
You can pass in a delimited list or JSON and use STRING_SPLIT() or OPENJSON().
STRING_SPLIT():
CREATE PROCEDURE dbo.DoSomethingWithEmployees
#List varchar(max)
AS
BEGIN
SET NOCOUNT ON;
SELECT value FROM STRING_SPLIT(#List, ',');
END
GO
EXEC dbo.DoSomethingWithEmployees #List = '1,2,3';
OPENJSON():
CREATE PROCEDURE dbo.DoSomethingWithEmployees
#List varchar(max)
AS
BEGIN
SET NOCOUNT ON;
SELECT value FROM OPENJSON(CONCAT('["',
REPLACE(STRING_ESCAPE(#List, 'JSON'),
',', '","'), '"]')) AS j;
END
GO
EXEC dbo.DoSomethingWithEmployees #List = '1,2,3';
I wrote more about this here:
Handling an unknown number of parameters in SQL Server
Ordered String Splitting in SQL Server with OPENJSON
SQL Server 2008 (or newer)
First, in your database, create the following two objects:
CREATE TYPE dbo.IDList
AS TABLE
(
ID INT
);
GO
CREATE PROCEDURE dbo.DoSomethingWithEmployees
#List AS dbo.IDList READONLY
AS
BEGIN
SET NOCOUNT ON;
SELECT ID FROM #List;
END
GO
Now in your C# code:
// Obtain your list of ids to send, this is just an example call to a helper utility function
int[] employeeIds = GetEmployeeIds();
DataTable tvp = new DataTable();
tvp.Columns.Add(new DataColumn("ID", typeof(int)));
// populate DataTable from your List here
foreach(var id in employeeIds)
tvp.Rows.Add(id);
using (conn)
{
SqlCommand cmd = new SqlCommand("dbo.DoSomethingWithEmployees", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvparam = cmd.Parameters.AddWithValue("#List", tvp);
// these next lines are important to map the C# DataTable object to the correct SQL User Defined Type
tvparam.SqlDbType = SqlDbType.Structured;
tvparam.TypeName = "dbo.IDList";
// execute query, consume results, etc. here
}
SQL Server 2005
If you are using SQL Server 2005, I would still recommend a split function over XML. First, create a function:
CREATE FUNCTION dbo.SplitInts
(
#List VARCHAR(MAX),
#Delimiter VARCHAR(255)
)
RETURNS TABLE
AS
RETURN ( SELECT Item = CONVERT(INT, Item) FROM
( SELECT Item = x.i.value('(./text())[1]', 'varchar(max)')
FROM ( SELECT [XML] = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>') + '</i>').query('.')
) AS a CROSS APPLY [XML].nodes('i') AS x(i) ) AS y
WHERE Item IS NOT NULL
);
GO
Now your stored procedure can just be:
CREATE PROCEDURE dbo.DoSomethingWithEmployees
#List VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
SELECT EmployeeID = Item FROM dbo.SplitInts(#List, ',');
END
GO
And in your C# code you just have to pass the list as '1,2,3,12'...
I find the method of passing through table valued parameters simplifies the maintainability of a solution that uses it and often has increased performance compared to other implementations including XML and string splitting.
The inputs are clearly defined (no one has to guess if the delimiter is a comma or a semi-colon) and we do not have dependencies on other processing functions that are not obvious without inspecting the code for the stored procedure.
Compared to solutions involving user defined XML schema instead of UDTs, this involves a similar number of steps but in my experience is far simpler code to manage, maintain and read.
In many solutions you may only need one or a few of these UDTs (User defined Types) that you re-use for many stored procedures. As with this example, the common requirement is to pass through a list of ID pointers, the function name describes what context those Ids should represent, the type name should be generic.
Based on my experience, by creating a delimited expression from the employeeIDs, there is a tricky and nice solution for this problem. You should only create an string expression like ';123;434;365;' in-which 123, 434 and 365 are some employeeIDs. By calling the below procedure and passing this expression to it, you can fetch your desired records. Easily you can join the "another table" into this query. This solution is suitable in all versions of SQL server. Also, in comparison with using table variable or temp table, it is very faster and optimized solution.
CREATE PROCEDURE dbo.DoSomethingOnSomeEmployees #List AS varchar(max)
AS
BEGIN
SELECT EmployeeID
FROM EmployeesTable
-- inner join AnotherTable on ...
where #List like '%;'+cast(employeeID as varchar(20))+';%'
END
GO
Use a table-valued parameter for your stored procedure.
When you pass it in from C# you'll add the parameter with the data type of SqlDb.Structured.
See here: http://msdn.microsoft.com/en-us/library/bb675163.aspx
Example:
// Assumes connection is an open SqlConnection object.
using (connection)
{
// Create a DataTable with the modified rows.
DataTable addedCategories =
CategoriesDataTable.GetChanges(DataRowState.Added);
// Configure the SqlCommand and SqlParameter.
SqlCommand insertCommand = new SqlCommand(
"usp_InsertCategories", connection);
insertCommand.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue(
"#tvpNewCategories", addedCategories);
tvpParam.SqlDbType = SqlDbType.Structured;
// Execute the command.
insertCommand.ExecuteNonQuery();
}
You need to pass it as an XML parameter.
Edit: quick code from my project to give you an idea:
CREATE PROCEDURE [dbo].[GetArrivalsReport]
#DateTimeFrom AS DATETIME,
#DateTimeTo AS DATETIME,
#HostIds AS XML(xsdArrayOfULong)
AS
BEGIN
DECLARE #hosts TABLE (HostId BIGINT)
INSERT INTO #hosts
SELECT arrayOfUlong.HostId.value('.','bigint') data
FROM #HostIds.nodes('/arrayOfUlong/u') as arrayOfUlong(HostId)
Then you can use the temp table to join with your tables.
We defined arrayOfUlong as a built in XML schema to maintain data integrity, but you don't have to do that. I'd recommend using it so here's a quick code for to make sure you always get an XML with longs.
IF NOT EXISTS (SELECT * FROM sys.xml_schema_collections WHERE name = 'xsdArrayOfULong')
BEGIN
CREATE XML SCHEMA COLLECTION [dbo].[xsdArrayOfULong]
AS N'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="arrayOfUlong">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded"
name="u"
type="xs:unsignedLong" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>';
END
GO
Context is always important, such as the size and complexity of the array. For small to mid-size lists, several of the answers posted here are just fine, though some clarifications should be made:
For splitting a delimited list, a SQLCLR-based splitter is the fastest. There are numerous examples around if you want to write your own, or you can just download the free SQL# library of CLR functions (which I wrote, but the String_Split function, and many others, are completely free).
Splitting XML-based arrays can be fast, but you need to use attribute-based XML, not element-based XML (which is the only type shown in the answers here, though #AaronBertrand's XML example is the best as his code is using the text() XML function. For more info (i.e. performance analysis) on using XML to split lists, check out "Using XML to pass lists as parameters in SQL Server" by Phil Factor.
Using TVPs is great (assuming you are using at least SQL Server 2008, or newer) as the data is streamed to the proc and shows up pre-parsed and strongly-typed as a table variable. HOWEVER, in most cases, storing all of the data in DataTable means duplicating the data in memory as it is copied from the original collection. Hence using the DataTable method of passing in TVPs does not work well for larger sets of data (i.e. does not scale well).
XML, unlike simple delimited lists of Ints or Strings, can handle more than one-dimensional arrays, just like TVPs. But also just like the DataTable TVP method, XML does not scale well as it more than doubles the datasize in memory as it needs to additionally account for the overhead of the XML document.
With all of that said, IF the data you are using is large or is not very large yet but consistently growing, then the IEnumerable TVP method is the best choice as it streams the data to SQL Server (like the DataTable method), BUT doesn't require any duplication of the collection in memory (unlike any of the other methods). I posted an example of the SQL and C# code in this answer:
Pass Dictionary to Stored Procedure T-SQL
As others have noted above, one way to do this is to convert your array to a string and then split the string inside SQL Server.
As of SQL Server 2016, there's a built-in way to split strings called
STRING_SPLIT()
It returns a set of rows that you can insert into your temp table (or real table).
DECLARE #str varchar(200)
SET #str = "123;456;789;246;22;33;44;55;66"
SELECT value FROM STRING_SPLIT(#str, ';')
would yield:
value
-----
123
456
789
246
22
33
44
55
66
If you want to get fancier:
DECLARE #tt TABLE (
thenumber int
)
DECLARE #str varchar(200)
SET #str = "123;456;789;246;22;33;44;55;66"
INSERT INTO #tt
SELECT value FROM STRING_SPLIT(#str, ';')
SELECT * FROM #tt
ORDER BY thenumber
would give you the same results as above (except the column name is "thenumber"), but sorted. You can use the table variable like any other table, so you can easily join it with other tables in the DB if you want.
Note that your SQL Server install has to be at compatibility level 130 or higher in order for the STRING_SPLIT() function to be recognized. You can check your compatibility level with the following query:
SELECT compatibility_level
FROM sys.databases WHERE name = 'yourdatabasename';
Most languages (including C#) have a "join" function you can use to create a string from an array.
int[] myarray = {22, 33, 44};
string sqlparam = string.Join(";", myarray);
Then you pass sqlparam as your parameter to the stored procedure above.
This will help you. :) Follow the next steps,
Open the Query Editor
Copy Paste the following code as it is, it will create the Function which converts the String to Int
CREATE FUNCTION dbo.SplitInts
(
#List VARCHAR(MAX),
#Delimiter VARCHAR(255)
)
RETURNS TABLE
AS
RETURN ( SELECT Item = CONVERT(INT, Item) FROM
( SELECT Item = x.i.value('(./text())[1]', 'varchar(max)')
FROM ( SELECT [XML] = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>') + '</i>').query('.')
) AS a CROSS APPLY [XML].nodes('i') AS x(i) ) AS y
WHERE Item IS NOT NULL
);
GO
Create the Following stored procedure
CREATE PROCEDURE dbo.sp_DeleteMultipleId
#List VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM TableName WHERE Id IN( SELECT Id = Item FROM dbo.SplitInts(#List, ','));
END
GO
Execute this SP Using exec sp_DeleteId '1,2,3,12' this is a string of Id's which you want to delete,
You can convert your array to string in C# and pass it as a Stored Procedure parameter as below,
int[] intarray = { 1, 2, 3, 4, 5 };
string[] result = intarray.Select(x=>x.ToString()).ToArray();
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandText = "sp_DeleteMultipleId";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#Id",SqlDbType.VARCHAR).Value=result ;
This will delete multiple rows in a single stored proc call. All the best.
There is no support for array in sql server but there are several ways by which you can pass collection to a stored proc .
By using datatable
By using XML.Try converting your collection in an xml format and then pass it as an input to a stored procedure
The below link may help you
passing collection to a stored procedure
Starting in SQL Server 2016 you can bring the list in as an NVARCHAR() and use OPENJSON
DECLARE #EmployeeList nvarchar(500) = '[1,2,15]'
SELECT *
FROM Employees
WHERE ID IN (SELECT VALUE FROM OPENJSON(#EmployeeList ))
I've been searching through all the examples and answers of how to pass any array to sql server without the hassle of creating new Table type,till i found this linK, below is how I applied it to my project:
--The following code is going to get an Array as Parameter and insert the values of that
--array into another table
Create Procedure Proc1
#UserId int, //just an Id param
#s nvarchar(max) //this is the array your going to pass from C# code to your Sproc
AS
declare #xml xml
set #xml = N'<root><r>' + replace(#s,',','</r><r>') + '</r></root>'
Insert into UserRole (UserID,RoleID)
select
#UserId [UserId], t.value('.','varchar(max)') as [RoleId]
from #xml.nodes('//root/r') as a(t)
END
Hope you enjoy it
Starting in SQL Server 2016 you can simply use split string
Example:
WHERE (#LocationId IS NULL OR Id IN (SELECT items from Split_String(#LocationId, ',')))
CREATE TYPE dumyTable
AS TABLE
(
RateCodeId int,
RateLowerRange int,
RateHigherRange int,
RateRangeValue int
);
GO
CREATE PROCEDURE spInsertRateRanges
#dt AS dumyTable READONLY
AS
BEGIN
SET NOCOUNT ON;
INSERT tblRateCodeRange(RateCodeId,RateLowerRange,RateHigherRange,RateRangeValue)
SELECT *
FROM #dt
END
It took me a long time to figure this out, so in case anyone needs it...
This is based on the SQL 2005 method in Aaron's answer, and using his SplitInts function (I just removed the delim param since I'll always use commas). I'm using SQL 2008 but I wanted something that works with typed datasets (XSD, TableAdapters) and I know string params work with those.
I was trying to get his function to work in a "where in (1,2,3)" type clause, and having no luck the straight-forward way. So I created a temp table first, and then did an inner join instead of the "where in". Here is my example usage, in my case I wanted to get a list of recipes that don't contain certain ingredients:
CREATE PROCEDURE dbo.SOExample1
(
#excludeIngredientsString varchar(MAX) = ''
)
AS
/* Convert string to table of ints */
DECLARE #excludeIngredients TABLE (ID int)
insert into #excludeIngredients
select ID = Item from dbo.SplitInts(#excludeIngredientsString)
/* Select recipies that don't contain any ingredients in our excluded table */
SELECT r.Name, r.Slug
FROM Recipes AS r LEFT OUTER JOIN
RecipeIngredients as ri inner join
#excludeIngredients as ei on ri.IngredientID = ei.ID
ON r.ID = ri.RecipeID
WHERE (ri.RecipeID IS NULL)
First, just to be clear, I recognize that ExecuteNonQuery should only be used for UPDATE, INSERT, or DELETE statements, and that for all other types of statements, such as SELECT, the return value is -1.
My question is, why does the following stored procedure:
CREATE PROCEDURE `ExampleProc`(IN Name varchar(60), OUT ID bigint(20), OUT SP varchar(255))
BEGIN
SELECT id, sp INTO ID, SP FROM users WHERE username = Name;
END
When executed using ExecuteNonQuery:
using (var conn = new MySqlConnection("Secret"))
{
conn.Open();
using (var cmd = new MySqlCommand("ExampleProc", conn) { CommandType = CommandType.StoredProcedure })
{
cmd.Parameters.AddWithValue("Name", request.Name).MySqlDbType = MySqlDbType.VarChar;
cmd.Parameters.Add("ID", MySqlDbType.Int64).Direction = ParameterDirection.Output;
cmd.Parameters.Add("SP", MySqlDbType.VarChar).Direction = ParameterDirection.Output;
var returnVal = cmd.ExecuteNonQuery();
}
}
Yield a 0 in returnVal when a row with Name is not found, and a 1 if it is found? Based on all the documentation I have read, since the stored procedure contains a single SELECT statement, I should be seeing -1 being returned no matter what. Instead, it's returning the number of rows affected/found, which doesn't make sense according to the documentation.
Lastly, I've also tried using just "SELECT *" instead of "SELECT id, sp INTO ID, SP". That seems to always return 0. Still not the -1 that I am expecting.
Let's understand the working of the ExecuteNonQuery API in the ADO.Net, as you have understood from the documentation that it shall provide the number of Rows impacted as part of DML query and -1 for the Select query.
However the internal working is such that in case of Sql Server, default setting is Set NoCount Off helps in writing to the TDS protocol, the number of modified rows and same is read by the Ado.Net APIs, thus the correct result, this is the result of native binary integration of ado.net with Sql Server. more details at the following links:
Ado.Net TDS Protocol
SET NOCOUNT ON usage
When it comes to other database, like MySql, Oracle, there's no guarantee of the same behavior, as their integration is not at same level as Sql Server. This is the main reason for discrepancy, posted in the question, to make it consistent across the database, you may want to rely of a Output Parameter to automatically fill the value internally in the procedure, since every database has mechanism to figure out the number of rows updated
I am struggling to understand why a certain stored procedure has stopped working in a few of my databases, but not in others. I am hoping that someone can help me resolve this issue.
Introduction
I inherited an existing C# application that connects to a choice of SQL Server databases depending on the culture parameter supplied to the program. Example: Passing "en-CA" causes the program to connect to the database with English-Canada content. Passing "fr-CA" causes the program to connect to the database with French-Canada content. The databases are derived from a common root database. The databases are essentially identical except for the contents of many of the NVARCHAR fields. (This variety of databases is used solely during development for testing various cultures.)
Both databases use the following collation: SQL_Latin1_General_CP1_CI_AS
Issue
I am not sure when this issue started, but the current situation is that if I call a certain stored procedure from the fr-CA database, then it is not executed at all. (I will explain this in more detail.) No error code is returned to the program. the program acts as if no record was found.
However, if I call the same stored procedure from the en-CA database, then it functions as expected and a record is returned to the program.
Attempted Steps
If I run the stored procedure from SSMS, then it executes properly.
I have attempted copying the definition of the stored procedure from the database where it is executing properly to the database where it is not executing properly. This did not resolve the issue.
I did try debugging with the SQL Profiler. When I ran the stored procedure against both databases, I see an entry in the trace. I do not see any errors listed. I will admit that I am a newbie when it comes to using the Profiler.
When I say that the stored procedure is not being executed, I base this on the following test. I created a debug table with a couple of fields:
create table DEBUG
(
Id INTEGER,
Line NVARCHAR(100)
);
At the top of the stored procedure, in both databases, I inserted as the very first line the following statement:
INSERT INTO dbo.DEBUG VALUES (1, 'Top of Atms_Get_Tray_Infos');
When my code calls the stored procedure, I expect to see a line in the DEBUG table.
If I run the program against the en-CA database, I do see the expected line:
If I empty the DEBUG table and then run the program against the fr-CA database, the DEBUG table remains empty. This fact leads me to believe that the stored procedure is not being executed.
Database details
Here is the definition of the stored procedure with the debug line:
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[Atms_Get_Tray_Infos]
#TrayNo AS NVARCHAR(10)
AS
BEGIN
-- DEBUG
INSERT INTO dbo.DEBUG VALUES (1, 'Top of Atms_Get_Tray_Infos');
-- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN TRY
SELECT HTRAY.SEQ_HIST_PLATEAU AS TRAYNO,
HTRAY.DATE_EXPIRATION_DATE AS EXPIRY,
HTRAY.DATE_UTILISATION_DATE AS DATEUSED,
HTRAY.LADATE_LAVAGE AS WASHDATE,
HSTE.SEQ_CODE_QUAL_STERIL AS QLTYCODE,
HSTE.NO_CHARGE AS CHGNO,
HSTE.TEST_BIO_BON AS BIOTEST,
FRML.CODE AS FORMULACODE,
TRAY.NO_TYPE_PLATEAU AS TRAYCODE,
TRAY.DESCRIPTION_S,
TRAY.EstUrgent AS URGENT
FROM dbo.HIST_PLAT HTRAY
LEFT JOIN dbo.HIST_CHARG_STE HSTE ON HTRAY.LAST_SEQ_HIST_CHARGE_STERIL = HSTE.SEQ_HIST_CHARGE_STERIL
INNER JOIN dbo.PLATEAUX TRAY ON TRAY.SEQ_PLATEAU = HTRAY.NO_SEQ_PLATEAU
INNER JOIN dbo.FORMULE FRML ON HSTE.SEQ_FORMULE = FRML.SEQ_FORMULE
WHERE HTRAY.SEQ_HIST_PLATEAU = #TrayNo
END TRY
BEGIN CATCH
DECLARE #ErrorMessage NVARCHAR(4000);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
SELECT #ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
RAISERROR (#ErrorMessage, #ErrorSeverity, #ErrorState);
END CATCH
END
I appreciate any bit of assistance that will lead me to a resolution of this issue. Thanks!
Paolo's comment, above, caused me to investigate the actual C# code that calls the stored procedure.
The code is convoluted for the sake of being convoluted, in my opinion.
There is a method is some class that handles all calls to stored procedures. I replaced that code with this basic code:
DataSet dataSet = new DataSet("ReturnDs");
using (var connection = new System.Data.SqlClient.SqlConnection(theConnectStg))
{
using (var command = new System.Data.SqlClient.SqlCommand(theStoreProcName, connection))
{
using (var dataAdapter = new System.Data.SqlClient.SqlDataAdapter(command))
{
command.CommandType = CommandType.StoredProcedure;
if (theParameterList != null)
{
foreach (String str1 in theParameterList.ToArray())
{
String parameterName = str1.Substring(0, str1.IndexOf(":"));
String str2 = str1.Substring(str1.IndexOf(":") + 1);
dataAdapter.SelectCommand.Parameters.Add(new SqlParameter(parameterName, SqlDbType.VarChar, 128));
dataAdapter.SelectCommand.Parameters[parameterName].Value = (object)str2;
}
}
dataAdapter.Fill(dataSet);
}
}
}
return dataSet;
To satisfy your curiosity, the theParameterList parameter is an array of parameters, each in the form "#variable:value". I'm not a fan, but I am stuck with the existing code for now.
So, why did the previous code fail for certain databases? I still do not know. I am curious, but I do not wish to spend any more time on this issue. My brain is tired.
Thanks for the clue, Paolo!
I have a stored procedure that is executing an INSERT statement that we are seeing significant delays when executing. When running it from our C# .NET application to insert 30 records in a row, it's taking roughly 4 seconds total to complete (only counting the tame it takes to run the SqlCommand.ExecuteNonQuery() method). However, calling the same exact stored procedure from within SQL Server Management Studio the same number of times only takes about 0.4 seconds. I can't figure out what's different between the 2 setups that would make such a difference of 10x speed.
I have tried all of the following with no noticeable change in speed:
Creating the stored procedure "WITH RECOMPILE"
Checking all of the "SET" values that are configured within SSMS and C#. The only difference one was SET ARITHABORT, which was ON in SSMS and OFF when called from the .NET application. Adding "SET ARITHABORT ON" to the start of the stored procedure made no difference, though.
Removed all default values from the sproc parameters
The code used to call the stored procedure from the .NET application is:
using (SqlConnection newConn = new SqlConnection(connectionString))
{
using (SqlCommand uCmd = new SqlCommand("sproc_name", newConn))
{
uCmd.CommandType = CommandType.StoredProcedure;
uCmd.Connection.Open();
//About 15 parameters added using:
uCmd.Parameters.AddWithValue("#ParamName", value);
...
//One output parameter
SqlParameter paramOUT = new SqlParameter("#OutPutKey", SqlDbType.UniqueIdentifier);
paramOUT.Direction = ParameterDirection.Output;
uCmd.Parameters.Add(paramOUT);
uCmd.ExecuteNonQuery();
uCmd.Connection.Close();
}
}
The stored procedure itself is just a list of set commands (SET ANSI_NULLS ON, SET QUOTED_IDENTIFIER ON, SET ARITHABORT ON), a list of non-defaulted parameters, and the setting of the output variable that will be the new uniqueidentifier that will be inserted as the primary key in the table, followed by the INSERT statement itself.
The application is build on .NET 4 and the SQL server is MS SQL Server 2005.
Here is an example of the insert stored procedure it's calling:
alter procedure InsertStuff
#Field1 uniqueidentifier,
#Field2 datetime,
...
#CreateDate datetime,
#PrimaryKEY uniqueidentifier OUTPUT
AS
declare #newCreateDate datetime
set #newCreateDate=getDate()
set #PrimaryKEY = NEWID()
INSERT INTO [dbo].[Table]
(
Field1,
Field2,
...
CreateDate,
PrimaryKEY
)
VALUES
(
#Field1,
#Field2,
...
#newCreateDate,
#PrimaryKEY
)
Likely the issue is that every execute command call does a network hop, where as ssms will send all 30 commands to the server at once in a batch. I believe by default SSMS will send all 30 statements as a single batch, but if you've changed other settings that may impact things as well.
Also, make sure youre not opening and closing the connection each time. While connection pools may make that a non issue, I wouldn't leave it to chance.
Here is my current implementation of a stored procedure which returns Order status for a given Order ID. There are two situations,
there is matched Order ID and I will retrieve the related status,
there is no matched Order ID (i.e. non-existing Order ID).
My confusion is, how to implement the two functions elegantly/efficiently in one stored procedure, so that I return matched Order ID for situation 1 and also indicate client no matched Order ID in situation 2?
I am using VSTS 2008 + C# + ADO.Net + .Net 3.5 as client, and using SQL Server 2008 as server.
CREATE PROCEDURE [dbo].[GetStatus]
#ID [nvarchar](256),
#Status [int] output
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT #Status = [Status]
FROM [dbo].[OrderStatus]
WHERE (#ID = [ID]);
END
thanks in advance,
George
why are you using output parameter.
you just need to take your stored procedure result in dataset of the data access layer.
just check that if (dataset != null) then take value else return appropriate message to your business layer.
There are multiple approaches you can take:
Keep everything as is and in your .NET code, if the #status value returned is DBNull, then it will indicate situation 2, otherwise situation 1.
Add a RETURN statement to the SPROC and use
Dim returnValue As New SqlParameter("#RETURN_VALUE", SqlDbType.Int)
returnValue.Direction = ParameterDirection.ReturnValue
Cmd.Parameters.Add(returnValue)
in your .NET code to explicitly identify what the SPROC returned and take action accordingly.
As an additional tip, use a SET instead of SELECT when assigning the value to #Status variable in the SPROC. This will guarantee that you get a NULL back if there is no match found. So,
`
-- Insert statements for procedure here
SET #Status = SELECT [Status]
FROM [dbo].[OrderStatus]
WHERE (#ID = [ID]);`
You can use the "if statements" inside the stored procedures. the web site at bottom gives you some tips.
http://translate.google.com.br/translate?u=http%3A%2F%2Fmail.firebase.com.br%2Fpipermail%2Flista_firebase.com.br%2F2005-November%2F021883.html&sl=pt&tl=en&hl=pt-BR&ie=UTF-8