I have the following, I could make it work as I want to but I think i'm doing it the wrong way, could you please explain how this could be done in a more efficient way ? While also looping on Categories and doing the same as with Districts within the same Insert() Method.
Thanks in advance.
#region Methods
public int Insert(List<District> Districts, List<Category> Categories)
{
StringBuilder sqlString = new StringBuilder("INSERT INTO Stores (name, image) VALUES (#Name, #Image);");
using (SqlConnection sqlConnection = new
SqlConnection(ConfigurationManager.ConnectionStrings["OahuDB"].ConnectionString))
{
SqlCommand sqlCommand = new SqlCommand(sqlString.ToString(), sqlConnection);
sqlCommand.Parameters.AddWithValue("#Name", this.Name);
sqlCommand.Parameters.AddWithValue("#Image", this.Image);
sqlConnection.Open();
int x = (int)sqlCommand.ExecuteScalar();
sqlString.Clear();
sqlCommand.Parameters.Clear();
foreach (District item in Districts)
{
sqlString.AppendLine("INSERT INTO districts_has_stores (district_id, store_id) VALUES (#DistrictID, #StoreID);");
sqlCommand.CommandText = sqlString.ToString();
sqlCommand.Parameters.AddWithValue("#DistrictID", item.ID);
sqlCommand.ExecuteNonQuery();
}
return x;
}
}
EDIT
Is is wrong to achieve the above by doing the following ?
sqlString.Clear();
sqlCommand.Parameters.Clear();
sqlString.AppendLine("INSERT INTO districts_has_stores (district_id, store_id) VALUES (#DistrictID, #StoreID);");
sqlCommand.CommandText = sqlString.ToString();
sqlCommand.Parameters.AddWithValue("#StoreID", x);
foreach (District item in Districts)
{
sqlCommand.Parameters.AddWithValue("#DistrictID", item.ID);
sqlCommand.ExecuteNonQuery();
}
sqlString.Clear();
sqlCommand.Parameters.Clear();
sqlString.AppendLine("INSERT INTO categories_has_stores (category_id, store_id) VALUES (#CategoryID, #StoreID);");
sqlCommand.CommandText = sqlString.ToString();
sqlCommand.Parameters.AddWithValue("#StoreID", x);
foreach (Category item in Categories)
{
sqlCommand.Parameters.AddWithValue("#CategoryID", item.ID);
sqlCommand.ExecuteNonQuery();
}
The first obvious thing is to move the invariant part of the sqlCommand out of the loop
sqlCommand.Parameters.Clear();
sqlString.Clear();
sqlString.AppendLine("INSERT INTO districts_has_stores (district_id, store_id) VALUES (#DistrictID, #StoreID);");
sqlCommand.CommandText = sqlString.ToString();
sqlCommand.Parameters.AddWithValue("#DistrictID", 0); // as dummy value
sqlCommand.Parameters.AddWithValue("#StoreID", x); // invariant
foreach (District item in Districts)
{
sqlCommand.Parameters["#DistrictID"].Value = item.ID;
sqlCommand.ExecuteNonQuery();
}
But this doesn't answer your fundamental problem. How to avoid hitting the database multiple times.
You could build a query with multiple inserts like this
sqlString.Clear();
sqlString.Append("INSERT INTO districts_has_stores (district_id, store_id) VALUES (");
foreach(District item in Districts)
{
sqlString.Append(item.ID.ToString);
sqlString.Append(", ")
sqlString.Append(x.ToString());
sqlString.Append("),");
}
sqlString.Length--;
sqlCommand.CommandText = sqlString.ToString()
But string concatenation is really a bad practice and I present this solution just as an example and I don't want to suggest this kind of approach.
The last possibility are Table-Valued Parameters (Only from SqlServer 2008).
First you need to create a Sql Type for the table you will pass in
CREATE TYPE dbo.DistrictsType AS TABLE
( DistrictID int, StoreID int )
and a StoredProcedure that will insert the data from the datatable passed in
CREATE PROCEDURE usp_InsertDistricts
(#tvpNewDistricts dbo.DistrictsType READONLY)
AS
BEGIN
INSERT INTO dbo.Districts (DistrictID, StoreID)
SELECT dt.DistrictID, dt.StoreID FROM #tvpNewDistricts AS dt;
END
then, back to your code you pass the district into the storedprocedure
(Probably you need to convert your List in a DataTable)
DataTable dtDistricts = ConvertListToDataTable(Districts);
SqlCommand insertCommand = new SqlCommand("usp_InsertDistricts", sqlConnection);
SqlParameter p1 = insertCommand.Parameters.AddWithValue("#tvpNewDistricts", dtDistricts);
p1.SqlDbType = SqlDbType.Structured;
p1.TypeName = "dbo.DistrictsType";
insertCommand.ExecuteNonQuery();
Well, if you look back at the link above, you will find other ways to pass your data in a single step to the database backend.... (Scroll to the end and you will find also a method that doesn't require a stored procedure on the database)
Assuming Stores has an identity column, in SQL Server, create a table type and a table-valued parameter to take advantage of it:
CREATE TYPE dbo.DistrictsTVP AS TABLE
(
DistrictID INT -- PRIMARY KEY? I hope so.
);
GO
CREATE PROCEDURE dbo.InsertStoreAndDistricts
#Name NVARCHAR(255),
#Image <some data type???>,
#Districts dbo.DistrictsTVP READONLY
AS
BEGIN
SET NOCOUNT ON;
DECLARE #StoreID INT;
INSERT dbo.Stores(name, [image]) SELECT #Name, #Image;
SET #StoreID = SCOPE_IDENTITY();
INSERT dbo.district_has_stores(district_id, store_id)
SELECT DistrictID, #StoreID
FROM #Districts;
END
GO
Then in C#, you can pass your List in directly without any looping:
using (...)
{
SqlCommand cmd = new SqlCommand("dbo.InsertStoreAndDistricts", sqlConnection);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvparam = cmd.Parameters.AddWithValue("#Districts", Districts);
tvparam.SqlDbType = SqlDbType.Structured;
// other params here - name and image
cmd.ExecuteNonQuery();
}
Recently in my project i used XML as a data type in my stored proc and did insert update and delete in just one shot instead of hitting the database multiple times .
Sample Stored proc
ALTER PROCEDURE [dbo].[insertStore]
#XMLDATA xml,
#name varchar(50),
#image datatype
AS
Begin
INSERT INTO Store
(name
,image
)
Select XMLDATA.item.value('#name[1]', 'varchar(10)') AS Name,
XMLDATA.item.value('#image[1]', 'yourData type') AS Image
FROM #XMLDATA.nodes('//Stores/InsertList/Store') AS XMLDATA(item)
END
Similarly you can write for update and delete .In C# u need to create the xml
public string GenerateXML(List<District> Districts)
var xml = new StringBuilder();
var insertxml = new StringBuilder();
xml.Append("<Stores>");
for (var i = 0; i < Districts.Count; i++)
{ var obj = Districts[i];
insertxml.Append("<Store");
insertxml.Append(" Name=\"" + obj.Name + "\" ");
insertxml.Append(" Image=\"" + obj.Image + "\" ");
insertxml.Append(" />");
}
xml.Append("<InsertList>");
xml.Append(insertxml.ToString());
xml.Append("</InsertList>");
SqlCommand cmd= new SqlCommand("insertStore",connectionString);
cmd.CommandType=CommandType.StoredProcedure;
SqlParameter param = new SqlParameter ();
param.ParameterName ="#XMLData";
param.value=xml;
paramter.Add(param);
cmd.ExecuteNonQuery();
Personally, I would create a stored procedure for the insert and pass in a Table-Valued param, which would allow you to do
INSERT tbl (f1, f2, ... fN)
SELECT * FROM #TVP
http://msdn.microsoft.com/en-us/library/bb510489.aspx
Unless you're using SQL 2005, then I would use an XML param in my stored proc and Serialize a collection to be inserted.
Think about your system design. Where is the data that you need to insert coming from? If it's already in the database, or another database, or some other kind of data store, you should be able to achieve a more bulk kind of transfer, simply inserting from one database to the other in a loop in stored procedure.
If the data is coming from a user, or some incompatible data store, like say an export from some third party program, then you basically have to realize that to get it into the database will involve quite of few round-trips to the database. You can use some tables, or XML or such , but those are actually closer to doing a bulk insert using other methods.
The bottom line is that SQL databases are designed to do inserts one at a time. This is 99% of the time OK because you are never asking users using the UI to type in thousands of things at one time.
Related
I just came across a situation where i had to insert multiple records into the database. The records i had were in generic list and now i have found two ways to insert multiple records.
i just do it as usual using ExecuteNonQuery and i use foreach loop to insert every records one by one(i don't think that this is the best way to do it since this way makes multiple trips to the database to insert the record).
using (SqlCommand cmd = new SqlCommand()
{
using (SqlConnection conn = new SqlConnection()
{
cmd.Connection = conn;
foreach (var entry in entries)
{
cmd.CommandText = "INSERT INTO Employees(id, name) VALUES
(#id,#name);";
cmd.Parameters.AddWithValue("#id", entry.Id);
cmd.Parameters.AddWithValue("#name", entry.Name);
cmd.ExecuteNonQuery();
}
}
}
i tried using SqlBulkCopy class i converted the Generic List to DataTable and used SqlBulkCopy.
using (SqlConnection con = new SqlConnection(consString))
{
using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(con))
{
sqlBulkCopy.DestinationTableName = "Employees";
con.Open();
sqlBulkCopy.WriteToServer(dt);
con.Close();
}
}
Both the methods do the intended work. But i want to know which is the best way. If there are any other better way to do this i am open to suggesstions.
Use Table-Valued Parameters (TVPs) ,which were introduced in SQL Server 2008. Before SQL Server 2008, it was not possible to pass a table variable in stored procedure as a parameter, after SQL Server now we can pass Table-Valued Parameter to send multiple rows of data to a stored procedure or a function without creating a temporary table or passing so many parameters. have a look at below example
CREATE TYPE UT_Employee AS TABLE
(
Emp_Id int NOT NULL,
EmployeeName nvarchar(MAX),
EmpSalary varchar(50),
StateId varchar(50),
CityId varchar(50)
)
CREATE PROCEDURE USP_Insert_Employee_Info
(
#Employee_Details [UT_Employee] READONLY
)
AS
BEGIN
INSERT INTO dbo.Employee
(
Emp_Id,
EmployeeName,
EmpSalary,
StateId,
CityId
)
SELECT * FROM #Employee_Details
END
Inserting multiple values into stored procedure as below
DECLARE #Employee_Details AS UT_Employee
INSERT INTO #Employee_Details
SELECT 1001,'Abcd',10000,101,21 UNION ALL
SELECT 1002,'dggg',20000,121,15 UNION ALL
SELECT 1003,'esse',22222,122,35 UNION ALL
SELECT 1004,'uyyy',44333,121,32 UNION ALL
SELECT 1005,'dghd',13233,656,87
EXEC dbo.USP_Insert_Employee_Info #Employee_Details = #Employee_Details
I'd normally use a Table-Valued Parameter for this. The explanation of how to do that is a bit long to put here, but check out Table-Valued Parameters on Microsoft Docs for how to do this.
Is there any way to parameterize an SQL INSERT statement (in C#), which inserts multiple rows? Currently I can think of only one way, to generate a statement for inserting mulitple rows, but that is quite open to SQL injection:
string sql = " INSERT INTO my_table"
+ " (a, b, c)"
+ " VALUES";
// Add each row of values to the statement
foreach (var item in collection) {
sql = sql
+ String.Format(" ({0}, {1}, {2}),",
aVal, bVal, cVal);
}
// Remove the excessive comma
sql = sql.Remove(sql.Length - 1);
What is the smarter/safer way to do this?
You could add paramaters inside the loop, like:
using (var comm = new SqlCommand()) {
var counter = 0;
foreach (var item in collection) {
sql = sql + String.Format(" (#a{0}, #b{0}, #c{0})," counter);
comm.Parameters.AddWithValue("#a" + counter, aVal);
comm.Parameters.AddWithValue("#b" + counter, bVal);
comm.Parameters.AddWithValue("#c" + counter, cVal);
counter++;
}
}
But I really wouldn't do a multi-row insert like this. IIRC the maximum amount of parameters in a query is about 2100, and this could get very big very fast. As you're looping through a collection anyway, you could just send it to the database in your loop, something like:
using (var con = new SqlConnection("connectionString here"))
{
con.Open();
var sql = "INSERT INTO my_table (a, b, c) VALUES (#a,#b,#c);"
using (var comm = new SqlCommand(sql, con))
{
comm.Parameters.Add("#a", SqlDbType.Int);
comm.Parameters.Add("#b", SqlDbType.NVarChar);
comm.Parameters.Add("#c", SqlDbType.Int);
foreach (var item in collection) {
{
comm.Parameters["#a"].Value = aVal;
comm.Parameters["#b"].Value = bVal;
comm.Parameters["#b"].Size = bVal.Length;
comm.Parameters["#c"].Value = cVal;
comm.ExecuteNonQuery();
}
}
}
The statement is prepared only once (and faster than a huge statement with 100's of parameters), and it doesn't fail all records when one record fails (add some exception handling for that). If you want to fail all when one record fails, you could wrap the thing up in a transaction.
Edit:
Ofcourse, when you regularly have to input 1000's of rows, this approach isn't the most efficient either, and your DBA might start to complain.
There are other approaches to this problem to remove the strain from the database: for example, create a stored procedure in your database that will insert the data from an xml document, or use Table Valued Parameters.
NYCdotNet wrote 2 nice blogs about these options, which I won't recreate here, but they're worth exploring (I'll paste some code below from the blog, as per guidelines, but credit where it's due: NYCdotNet)
XML document approach
Table Valued Parameters
The "meat" from the blog about TVP (in VB.NET but that shouldn't matter):
So I created this "generic" table-valued type:
CREATE TYPE dbo.UniqueIntegerList AS TABLE
(
TheInteger INT NOT NULL
PRIMARY KEY (TheInteger)
);
Creating the Save Stored Procedure
Next, I created a new stored procedure which would accept my new
Table-Valued Type as a parameter.
CREATE PROC DoTableValuedParameterInsert(#ProductIDs
dbo.UniqueIntegerList READONLY)
AS BEGIN
INSERT INTO ProductsAccess(ProductID)
SELECT TheInteger AS [ProductID]
FROM #ProductIDs;
END
In this procedure, I am passing in a parameter called #ProductIDs.
This is of type "dbo.UniqueIntegerList" which I just created in the
previous step. SQL Server looks at this and says "oh I know what this
is - this type is actually a table". Since it knows that the
UniqueIntegerList type is a table, I can select from it just like I
could select from any other table-valued variable. You have to mark
the parameter as READONLY because SQL 2008 doesn't support updating
and returning a passed table-valued parameter.
Creating the Save Routine
Then I had to create a new save routine on my business object that
would call the new stored procedure. The way you prepare the
Table-Valued parameter is to create a DataTable object with the same
column signature as the Table-Valued type, populate it, and then pass
it inside a SqlParameter object as SqlDbType.Structured.
Public Sub SaveViaTableValuedParameter()
'Prepare the Table-valued Parameter'
Dim objUniqueIntegerList As New DataTable
Dim objColumn As DataColumn =
objUniqueIntegerList.Columns.Add("TheInteger", _
System.Type.GetType("System.Int32"))
objColumn.Unique = True
'Populate the Table-valued Parameter with the data to save'
For Each Item As Product In Me.Values
objUniqueIntegerList.Rows.Add(Item.ProductID)
Next
'Connect to the DB and save it.'
Using objConn As New SqlConnection(DBConnectionString())
objConn.Open()
Using objCmd As New SqlCommand("dbo.DoTableValuedParameterInsert")
objCmd.CommandType = CommandType.StoredProcedure
objCmd.Connection = objConn
objCmd.Parameters.Add("ProductIDs", SqlDbType.Structured)
objCmd.Parameters(0).Value = objUniqueIntegerList
objCmd.ExecuteNonQuery()
End Using
objConn.Close()
End Using
End Sub
Using C# in Visual Studio, I'm inserting a row into a table like this:
INSERT INTO foo (column_name)
VALUES ('bar')
I want to do something like this, but I don't know the correct syntax:
INSERT INTO foo (column_name)
VALUES ('bar')
RETURNING foo_id
This would return the foo_id column from the newly inserted row.
Furthermore, even if I find the correct syntax for this, I have another problem: I have SqlDataReader and SqlDataAdapter at my disposal. As far as I know, the former is for reading data, the second is for manipulating data. When inserting a row with a return statement, I am both manipulating and reading data, so I'm not sure what to use. Maybe there's something entirely different I should use for this?
SCOPE_IDENTITY returns the last identity value inserted into an identity column in the same scope. A scope is a module: a stored procedure, trigger, function, or batch. Therefore, two statements are in the same scope if they are in the same stored procedure, function, or batch.
You can use SqlCommand.ExecuteScalar to execute the insert command and retrieve the new ID in one query.
using (var con = new SqlConnection(ConnectionString)) {
int newID;
var cmd = "INSERT INTO foo (column_name)VALUES (#Value);SELECT CAST(scope_identity() AS int)";
using (var insertCommand = new SqlCommand(cmd, con)) {
insertCommand.Parameters.AddWithValue("#Value", "bar");
con.Open();
newID = (int)insertCommand.ExecuteScalar();
}
}
try this:
INSERT INTO foo (column_name)
OUTPUT INSERTED.column_name,column_name,...
VALUES ('bar')
OUTPUT can return a result set (among other things), see: OUTPUT Clause (Transact-SQL). Also, if you insert multiple values (INSERT SELECT) this method will return one row per inserted row, where other methods will only return info on the last row.
working example:
declare #YourTable table (YourID int identity(1,1), YourCol1 varchar(5))
INSERT INTO #YourTable (YourCol1)
OUTPUT INSERTED.YourID
VALUES ('Bar')
OUTPUT:
YourID
-----------
1
(1 row(s) affected)
I think you can use ##IDENTITY for this, but I think there's some special rules/restrictions around it?
using (var con = new SqlConnection("connection string"))
{
con.Open();
string query = "INSERT INTO table (column) VALUES (#value)";
var command = new SqlCommand(query, con);
command.Parameters.Add("#value", value);
command.ExecuteNonQuery();
command.Parameters.Clear();
command.CommandText = "SELECT ##IDENTITY";
int identity = Convert.ToInt32(command.ExecuteScalar());
}
Using C# in Visual Studio, I'm inserting a row into a table like this:
INSERT INTO foo (column_name)
VALUES ('bar')
I want to do something like this, but I don't know the correct syntax:
INSERT INTO foo (column_name)
VALUES ('bar')
RETURNING foo_id
This would return the foo_id column from the newly inserted row.
Furthermore, even if I find the correct syntax for this, I have another problem: I have SqlDataReader and SqlDataAdapter at my disposal. As far as I know, the former is for reading data, the second is for manipulating data. When inserting a row with a return statement, I am both manipulating and reading data, so I'm not sure what to use. Maybe there's something entirely different I should use for this?
SCOPE_IDENTITY returns the last identity value inserted into an identity column in the same scope. A scope is a module: a stored procedure, trigger, function, or batch. Therefore, two statements are in the same scope if they are in the same stored procedure, function, or batch.
You can use SqlCommand.ExecuteScalar to execute the insert command and retrieve the new ID in one query.
using (var con = new SqlConnection(ConnectionString)) {
int newID;
var cmd = "INSERT INTO foo (column_name)VALUES (#Value);SELECT CAST(scope_identity() AS int)";
using (var insertCommand = new SqlCommand(cmd, con)) {
insertCommand.Parameters.AddWithValue("#Value", "bar");
con.Open();
newID = (int)insertCommand.ExecuteScalar();
}
}
try this:
INSERT INTO foo (column_name)
OUTPUT INSERTED.column_name,column_name,...
VALUES ('bar')
OUTPUT can return a result set (among other things), see: OUTPUT Clause (Transact-SQL). Also, if you insert multiple values (INSERT SELECT) this method will return one row per inserted row, where other methods will only return info on the last row.
working example:
declare #YourTable table (YourID int identity(1,1), YourCol1 varchar(5))
INSERT INTO #YourTable (YourCol1)
OUTPUT INSERTED.YourID
VALUES ('Bar')
OUTPUT:
YourID
-----------
1
(1 row(s) affected)
I think you can use ##IDENTITY for this, but I think there's some special rules/restrictions around it?
using (var con = new SqlConnection("connection string"))
{
con.Open();
string query = "INSERT INTO table (column) VALUES (#value)";
var command = new SqlCommand(query, con);
command.Parameters.Add("#value", value);
command.ExecuteNonQuery();
command.Parameters.Clear();
command.CommandText = "SELECT ##IDENTITY";
int identity = Convert.ToInt32(command.ExecuteScalar());
}
I am calling a SQL Server stored procedure from my C# code:
using (SqlConnection conn = new SqlConnection(connstring))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("InsertQuerySPROC", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
var STableParameter = cmd.Parameters.AddWithValue("#QueryTable", QueryTable);
var NDistanceParameter = cmd.Parameters.AddWithValue("#NDistanceThreshold", NDistanceThreshold);
var RDistanceParameter = cmd.Parameters.AddWithValue(#"RDistanceThreshold", RDistanceThreshold);
STableParameter .SqlDbType = SqlDbType.Structured;
NDistanceParameter.SqlDbType = SqlDbType.Int;
RDistanceParameter.SqlDbType = SqlDbType.Int;
// Execute the query
SqlDataReader QueryReader = cmd.ExecuteReader();
My stored proc is fairly standard but does a join with QueryTable (hence the need for for using a stored proc).
Now: I want to add a list of strings, List<string>, to the parameter set. For example, my stored proc query goes like this:
SELECT feature
FROM table1 t1
INNER JOIN #QueryTable t2 ON t1.fid = t2.fid
WHERE title IN <LIST_OF_STRINGS_GOES_HERE>
However, the list of strings is dynamic and a few hundred long.
Is there a way to pass a list of strings List<string> to the stored proc??? Or is there a better way to do this?
Many thanks,
Brett
If you're using SQL Server 2008, there's a new featured called a User Defined Table Type. Here is an example of how to use it:
Create your User Defined Table Type:
CREATE TYPE [dbo].[StringList] AS TABLE(
[Item] [NVARCHAR](MAX) NULL
);
Next you need to use it properly in your stored procedure:
CREATE PROCEDURE [dbo].[sp_UseStringList]
#list StringList READONLY
AS
BEGIN
-- Just return the items we passed in
SELECT l.Item FROM #list l;
END
Finally here's some sql to use it in c#:
using (var con = new SqlConnection(connstring))
{
con.Open();
using (SqlCommand cmd = new SqlCommand("exec sp_UseStringList #list", con))
{
using (var table = new DataTable()) {
table.Columns.Add("Item", typeof(string));
for (int i = 0; i < 10; i++)
table.Rows.Add("Item " + i.ToString());
var pList = new SqlParameter("#list", SqlDbType.Structured);
pList.TypeName = "dbo.StringList";
pList.Value = table;
cmd.Parameters.Add(pList);
using (var dr = cmd.ExecuteReader())
{
while (dr.Read())
Console.WriteLine(dr["Item"].ToString());
}
}
}
}
To execute this from SSMS
DECLARE #list AS StringList
INSERT INTO #list VALUES ('Apple')
INSERT INTO #list VALUES ('Banana')
INSERT INTO #list VALUES ('Orange')
-- Alternatively, you can populate #list with an INSERT-SELECT
INSERT INTO #list
SELECT Name FROM Fruits
EXEC sp_UseStringList #list
The typical pattern in this situation is to pass the elements in a comma delimited list, and then in SQL split that out into a table you can use. Most people usually create a specified function for doing this like:
INSERT INTO <SomeTempTable>
SELECT item FROM dbo.SplitCommaString(#myParameter)
And then you can use it in other queries.
No, arrays/lists can't be passed to SQL Server directly.
The following options are available:
Passing a comma-delimited list and then having a function in SQL split the list. The comma delimited list will most likely be passed as an Nvarchar()
Pass xml and have a function in SQL Server parse the XML for each value in the list
Use the new defined User Defined table type (SQL 2008)
Dynamically build the SQL and pass in the raw list as "1,2,3,4" and build the SQL statement. This is prone to SQL injection attacks, but it will work.
Yep, make Stored proc parameter as VARCHAR(...)
And then pass comma separated values to a stored procedure.
If you are using Sql Server 2008 you can leverage TVP (Table Value Parameters): SQL 2008 TVP and LINQ if structure of QueryTable more complex than array of strings otherwise it would be an overkill because requires table type to be created within SQl Server
Make a datatable with one column instead of List and add strings to the table. You can pass this datatable as structured type and perform another join with title field of your table.
If you prefer splitting a CSV list in SQL, there's a different way to do it using Common Table Expressions (CTEs). See Efficient way to string split using CTE.
The only way I'm aware of is building CSV list and then passing it as string. Then, on SP side, just split it and do whatever you need.
CREATE TYPE [dbo].[StringList1] AS TABLE(
[Item] [NVARCHAR](MAX) NULL,
[counts][nvarchar](20) NULL);
create a TYPE as table and name it as"StringList1"
create PROCEDURE [dbo].[sp_UseStringList1]
#list StringList1 READONLY
AS
BEGIN
-- Just return the items we passed in
SELECT l.item,l.counts FROM #list l;
SELECT l.item,l.counts into tempTable FROM #list l;
End
The create a procedure as above and name it as "UserStringList1"
s
String strConnection = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString.ToString();
SqlConnection con = new SqlConnection(strConnection);
con.Open();
var table = new DataTable();
table.Columns.Add("Item", typeof(string));
table.Columns.Add("count", typeof(string));
for (int i = 0; i < 10; i++)
{
table.Rows.Add(i.ToString(), (i+i).ToString());
}
SqlCommand cmd = new SqlCommand("exec sp_UseStringList1 #list", con);
var pList = new SqlParameter("#list", SqlDbType.Structured);
pList.TypeName = "dbo.StringList1";
pList.Value = table;
cmd.Parameters.Add(pList);
string result = string.Empty;
string counts = string.Empty;
var dr = cmd.ExecuteReader();
while (dr.Read())
{
result += dr["Item"].ToString();
counts += dr["counts"].ToString();
}
in the c#,Try this