Save multiple rows in one table in one connection IN sqlserver - c#

Scenario: Just consider i have a table having 3 column Id, QuestionId and optedAnswer. I have a form which consists n no of question and some options for answer. On save button i want to save data in database(in my table).
Problem: I want to save all the answers in one connection.
Step taken by me: I made a string having structure questionId:optedAnswwer | questionId : optedAnswer | and so on....
I wrote a procedure. started a loop. split the data based on ':' and '|' and saved data in one connection. But it is a rigorous task. Is there any way to save the data directly without using loop and split.

Save your each questionId and its OptedAnswer in Datatable and then insert your datatable to SQL table as below :
DataTable dataTable = null; // your data needs to be here
try
{
ConnectionStringSettings mConString = ConfigurationManager.ConnectionStrings["SiteSqlServer"];
// Optional truncating old table
using (SqlConnection connection = new SqlConnection(mConString.ConnectionString))
{
connection.Open();
// Delete old entries
SqlCommand truncate = new SqlCommand("TRUNCATE TABLE MYTABLE", connection);
truncate.ExecuteNonQuery();
}
SqlBulkCopy bulkCopy = new SqlBulkCopy(mConString.ConnectionString, SqlBulkCopyOptions.TableLock)
{
DestinationTableName = "dbo.MYTABLE",
BatchSize = 100, //set your required size
BulkCopyTimeout = 360
};
bulkCopy.WriteToServer(dataTable);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}

Create a XML string of all your queastion and ans and pass these xml string to sql and use the
sp_xml_preparedocument procedure these sql inbuilt proc that reads the XML.
you can get more information on Bulk INsert

I would also go for an xml-centric solution, prepare you data in an xmldocument, post that inte the database and use a SELECT from the xml as source for your insert eg:
declare #xml XML
DECLARE #docid int
set #xml = N'<?xml version="1.0" ?>
<Custs>
<Cust>
<name>Erik</name>
<lastname>Stark</lastname>
</Cust>
<Cust>
<name>Donald</name>
<lastname>Duck</lastname>
</Cust>
<Cust>
<name>Johnny</name>
<lastname>Walker</lastname>
</Cust>
</Custs>'
EXEC sp_xml_preparedocument #docid OUTPUT, #xml
SELECT *
FROM OPENXML (#docid, '/Custs/Cust',2)
WITH (name varchar(50), lastname varchar(50))
exec sp_xml_removedocument #docid

There is another way to save multiple data in one connection.
Create a type of table like this
CREATE TYPE [dbo].[YourTypeName] AS TABLE(
[Col1] [bigint] NULL,
[Col2] [datetime] NULL,
[Col3] [bigint] NULL,
[Col4] [bigint] NULL,
[Col5] [datetime] NULL
)
and then write a procedure like this....
CREATE PROCEDURE [dbo].YOURPROCEDURENAME]
(
#yourDataTableName YourTypeName READONLY
)
AS
INSERT INTO TableName
(Col1,
Col2,
Col3,
Col4,
Col5)
SELECT CP.Val1,
CP.Val2,
CP.Val3,
CP.Val4,
CP.Val15)
FROM #yourDataTableName CP
GO
And then create a datatable in code behind and pass that datatable in prosedure like this...
SqlCommand cmd = new SqlCommand("YOURPROCEDURENAME");
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#yourDataTableName", SqlDbType.Structured).Value = datatable;
cmd.Parameters[0].TypeName = "YourTypeName ";

Related

C# + Reading output result from stored procedure + merge into + OUTPUT

I am trying to upload an Excel file in C# to SQL Server database table.
The table looks like this:
Companies
ID(PK) Int AutoIncrement
CompanyName Varchar(256)
Logo Varchar(256)
WebsiteURL Varchar(256)
Description Varchar(256)
I have read the Excel into a DataTable object and passed it to a stored procedure. The stored procedure uses MERGE INTO to insert new records and update existing.
I need to know how many records are inserted and how many are updated.
For this, I used OUTPUT like this:
CREATE PROCEDURE [dbo].[Update_Companies]
#tblCompanies CompanyType READONLY
AS
BEGIN
SET NOCOUNT ON;
DECLARE #summary CompanySummaryType;
MERGE INTO companies c1
USING #tblCompanies c2 ON c1.CompanyName = c2.CompanyName
WHEN MATCHED THEN
UPDATE
SET c1.Logo = c2.Logo,
c1.WebsiteURL = c2.WebsiteURL,
c1.CompanyDescription = c2.CompanyDescription,
WHEN NOT MATCHED THEN
INSERT (CompanyName, Logo, WebsiteURL, Description)
VALUES (c2.CompanyName, c2.Logo, c2.WebsiteURL, c2.Description)
OUTPUT
$action as ActionType,
INSERTED.CompanyName as CompanyName INTO #summary;
END
CompanyType is a user-defined table type containing table columns
CompanySummaryType is a user-defined table type containing two columns:
ActionType Varchar(256),
CompanyName Varchar(256)
The code runs fine and insert or update working perfectly.
I want to read the #summary variable back in my C# code.
Right now, I am using ExecuteNonQuery to execute stored procedure like this:
private void AddRecords(DataTable dataTable)
{
string constr = ConfigurationManager.ConnectionStrings["CMSConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand("Update_Companies"))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con;
cmd.Parameters.AddWithValue("#tblCompanies", dataTable);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
}
}
Also, is there a way by which I can find how many records failed to insert or update?
You can make your #Summary variable an OUTPUT parameter of the procedure.
In your C# code, you can then compare the returned OUTPUT parameter, with the original input parameter, to see which rows were not inserted or updated.

How create a row and take his id at the same time in sql server and c#

I'm having a simple problem but cant find a solution:
I'm creating a row in my table client, but I don't know how recovery the id of the table that I just created, for example:
ALTER proc [dbo].[spinsert_client]
#idclient int output,
#name varchar(20),
#surname varchar(40),
as
insert into client(name,surname)
values (#name,#surname)
here I insert a client, now I want recovery that exact same idclient to insert "products" with it without have to manually search this client , I tried recovering the last row of the client table but I realise that if more than one person is using the same database in different computers it can be a problem, so I need create a client and recovery his id at the same time (it is an assumption I don't know). Im using sql server and Visual studio with c#
sorry for my bad English and thanks for the attention
edit-------------------
solution:
ALTER proc [dbo].[spinsert_client]
#idclient int output,
#name varchar(20),
#surname varchar(40)
as
insert into client(name,surname)
values (#name,#surname)
Select ##IDENTITY as newId;
them in my c# code:
rpta= SqlCmd.ExecuteScalar().ToString();
The best way is to use the OUTPUT clause. Here is an example that just captures the new id:
ALTER proc [dbo].[spinsert_client] (
#idclient int output,
#name varchar(20),
#surname varchar(40)
)
as
begin
declare #output table (idclient int);
insert into client(name, surname)
output inserted.idclient into #output;
values (#name, #surname);
select *
from #output;
end; -- spinsert_client
In your C# code you have somewhere a sql Statement defined:
string sqlStatement = "INSERT INTO ... (field list) OUTPUT INSERTED.yourfieldwithid values (value list) ";
and use it with ExecuteScalar() for getting the result value (I assume you know how to use Connection and command object)
You can do this:
string query = "INSERT INTO client" +
" (name, surname)" +
" VALUES (#Name, #Surname);" +
" SELECT SCOPE_IDENTITY();";
using (var dbconn = new SqlConnection("your connection string here") )
using (var dbcm = new SqlCommand(query, dbconn) )
{
dbcm.Parameters.Add("#Name", SqlDbType.VarChar, 20).Value = "name value";
dbcm.Parameters.Add("#Surname", SqlDbType.VarChar, 40).Value = "surname value";
dbconn.Open();
var insertedID = (int)dbcm .ExecuteScalar();
}
Check this SO post explaining every way of retrieving the inserted id from the table.
To answer your question, both OUTPUT_CLAUSE and IDENT_CURRENT can be used in this scenario but i would recomment IDENT_CURRENT because an OUTPUT clause will return rows to the client even if the statement encounters errors and is rolled back.
Use it like:
using (SqlCommand com = new SqlCommand("INSERT INTO cient(name, surname)"+
"VALUES (#Name, #Surname) SELECT IDENT_CURRENT('client'); ", con))
I would not suggest SCOPE_IDENTITY or ##IDENTITY because it may return wrong values (null) if you're not using SQL Server 2008 R2 SP2 or higher ( source - last row from the page.) especially for your requirement (inserting the value in some other table).

Passing array to a SQL Server Stored Procedure

How can I pass an array variable to a SQL Server stored procedure using C# and insert array values into a whole row?
Thanks in advance.
SQL Server table:
ID | Product | Description
-------------------------------
8A3H | Soda | 600ml bottle
C# array:
string[] info = new string[] {"7J9P", "Soda", "2000ml bottle"};
SQL Server stored procedure:
ALTER PROC INSERT
(#INFO_ARRAY ARRAY)
AS
BEGIN
INSERT INTO Products VALUES (#INFO_ARRAY)
END
In SQL Server 2008 and later
Create a type in SQL Server like so:
CREATE TYPE dbo.ProductArray
AS TABLE
(
ID INT,
Product NVARCHAR(50),
Description NVARCHAR(255)
);
Alter your procedure in SQL Server:
ALTER PROC INSERT_SP
#INFO_ARRAY AS dbo.ProductArray READONLY
AS
BEGIN
INSERT INTO Products SELECT * FROM #INFO_ARRAY
END
Then you'll need to create a DataTable object with values to pass in C#:
DataTable dt = new DataTable();
//Add Columns
dt.Columns.Add("ID");
dt.Columns.Add("Product");
dt.Columns.Add("Description");
//Add rows
dt.Rows.Add("7J9P", "Soda", "2000ml bottle");
using (conn)
{
SqlCommand cmd = new SqlCommand("dbo.INSERT_SP", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter dtparam = cmd.Parameters.AddWithValue("#INFO_ARRAY", dt);
dtparam.SqlDbType = SqlDbType.Structured;
}
here is a way simpler example:
I've been searching through all the examples and answers of how to pass any array to sql server,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
#INFO_ARRAY ARRAY nvarchar(max) //this is the array your going to pass from C# code
AS
declare #xml xml
set #xml = N'<root><r>' + replace(#INFO_ARRAY,',','</r><r>') + '</r></root>'
Insert into Products
select
t.value('.','varchar(max)')
from #xml.nodes('//root/r') as a(t)
END
Hope you enjoy it

How to insert a multiple rows in SQL using stored procedures?

I'm able to insert the the items in a single statement but what I want to do is to have another version using a Stored Procedures. How do I do that. Here's my code:
private void button1_Click(object sender, EventArgs e)
{
#region Get Values
string[] array = {textBox1.Text+":"+textBox5.Text,textBox2.Text+":"+textBox6.Text,textBox3.Text+":"+textBox7.Text,textBox4.Text+":"+textBox8.Text};
string query = "";
string product = "";
int qty = 0;
for (int i = 0; i < array.Length; i++ )
{
product = array[i].ToString().Substring(0,array[i].ToString().IndexOf(':'));
qty = int.Parse(array[i].ToString().Substring(array[i].ToString().IndexOf(':')+1));
if (string.IsNullOrEmpty(query))
{
query = "Insert Into MySampleTable Values ('"+product+"','"+qty+"')";
}
else
{
query += ",('" + product + "','" + qty + "')";
}
}
#endregion
string connect = "Data Source=RANDEL-PC;Initial Catalog=Randel;Integrated Security=True";
SqlConnection connection = new SqlConnection(connect);
connection.Open();
string insert = query;
SqlCommand command = new SqlCommand(query,connection);
command.ExecuteNonQuery();
command.Dispose();
connection.Close();
connection.Dispose();
label5.Visible = true;
label5.Text = insert;
}
}
Sir/Ma'am, Your answers would be of great help and be very much appreciated. Thank you++
In SQL Server 2008+ there are easier ways to insert multiple rows in a single statement. For example this syntax is valid:
INSERT dbo.table(col1, col2) VALUES
(1, 2),
(2, 3),
(3, 4);
The above will insert three rows. On older versions you can do slightly more verbose things such as:
INSERT dbo.table(col1, col2)
SELECT 1, 2
UNION ALL SELECT 2, 3
UNION ALL SELECT 3, 4;
Of course your ExecuteNonQuery does not have to be a single command, you can pass this as a single string and it will still work:
INSERT dbo.table(col1, col2) VALUES(1, 2);
INSERT dbo.table(col1, col2) VALUES(2, 3);
INSERT dbo.table(col1, col2) VALUES(3, 4);
If you want to do this in a stored procedure, you can easily perform a split on multi-valued parameters, for example if you pass in the following string:
1,2;2,3;3,4
You could process those values using a function like the one I posted here:
Split value pairs and a create table using UDF
So your procedure might look like this:
CREATE PROCEDURE dbo.AddOrderLineItems
#LineItems VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.OrderItems(Product, Quantity)
SELECT Product, Quantity FROM dbo.MultiSplit(#LineItems);
END
GO
And you would call it using the C# equivalent of:
EXEC dbo.AddOrderLineItems #LineItems = '1,2;2,3;3,4';
Or you could use table-valued parameters as suggested by Alexey. A quick example:
CREATE TYPE OrderLineItem AS TABLE
(
Product INT,
Quantity INT
);
Then you can create a procedure:
CREATE PROCEDURE dbo.AddOrderLineItems
#LineItems OrderLineItem READONLY
-- other parameters
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.OrderItems(Product, Quantity)
SELECT Product, Quantity FROM #LineItems;
END
GO
Then create the equivalent TVP in your C# code (I'm not the guy you want doing that; you can see an example here).
However there are some caveats, please look at this question:
Creating a generalized type for use as a table value parameter
If you want to pass multiple values into a stored procedure you have two ways:
And ugly one: pass your values as a separate string, split it in your store procedure, do bulk insert. You will find tonnes of examples of it in Google.
A clever one: use table-value parameters, the feature supported by both ADO.NET and SQL Server. Then you will be able to pass a parameter value and have it as a normal table variable in your stored procedure.

How can I prevent inserting duplicate data into a SQL Server table?

I have a series of data that need to be written into SQL, what should I do to check the data in SQL to prevent same data inserted into table?
Example data to be inserted:
David
James
John
If the 4th data is John again, I want the system to skip the duplicate record (John).
So far I have:
SqlConnection myCnn = new SqlConnection(cnn);
String _state = "Insert into CamNo1(platename, date, camID, path, filename) OUTPUT INSERTED.platename values(#msg, getdate(), #camID, #path, #filename)";
SqlCommand _Query = new SqlCommand(_state, myCnn);
_Query.Parameters.AddWithValue("#msg", msg);
_Query.Parameters.AddWithValue("#camID", camID);
_Query.Parameters.AddWithValue("#path", imageFile);
_Query.Parameters.AddWithValue("#filename", name);
try
{
myCnn.Open();
string checkname = (string)_Query.ExecuteScalar();
myCnn.Close();
getcheckname = checkname;
Console.WriteLine("OK");
}
catch (Exception)
{
}
i got the string value checkname that is last inserted, what should i do check the data?
First, you can prevent a duplicate from ever occurring in the table by using a unique index or constraint. An index/constraint can work in concert with the suggestions below. If you only use a unique index and not one of the below solutions, inserting a duplicate record will throw an error and you will need to handle that on the other end.
Additionally, I would probably insert the data via a stored procedure that checks to see if the row already exists. To do that, you can use either a MERGE statement, as shown in this pseudo code:
create procedure MyProcedure
(
#Name nvarchar(100),
...
)
as
merge MyTable
using
(
select #Name,...
) as source (Name, ...)
on MyTable.Name = source.Name
when not matched then
insert (Name,...) values (source.Name,...)
when matched then
update set Name = #Name,...
or, you could check for the records existence and insert or update manually:
create procedure MyProcedure
(
#Name nvarchar(100),
...
)
as
if not exists (select * from MyTable where Name = #Name)
begin
insert into MyTable (Name,...) values (#Name,...)
end
else
begin
update MyTable
set ...
where Name = #Name
end
If you do not want duplicate data, you should consider enforcing that at the DB level with a UNIQUE CONSTRAINT or a UNIQUE INDEX
SQL Server 2008 also has a MERGE statement you could use to check for matched records. This could be helpful if you want to update an existing record.
If you want to prevent duplicate data from being inserted, you could use a unique index or unique constraint on those fields.
If you want to just run a hard insert statement, but have it do nothing if a value exists, something like this should work. I tested this on a local database I have:
declare #subject as varchar(100);
set #subject = 'hello'
insert into Subjects ([name])
select #subject
where not exists (select 1 from Subjects where [name] = #Subject)
Try This Easy way
{
DataSet ds = New DataSet();
SqlConnection myCnn = New SqlConnection(cnn);
myCnn.Open();
SqlCommand _Query = New SqlCommand("Select *FROM CamNo1 where platename='" + Console.ReadLine + "' ", myCnn);
SqlDataAdapter sda = New SqlDataAdapter(_Query);
sda.Fill(ds);
Int i = ds.Tables[0].Rows.Count;
If (i > 0) Then
{
MessageBox.Show("platename" + Console.WriteLine + "Already Exists ");
ds.Clear();
}
Else
{
SqlConnection myCnn = New SqlConnection(cnn);
String _state = "Insert into CamNo1(platename, date, camID, path, filename) OUTPUT INSERTED.platename values(#msg, getdate(), #camID, #path, #filename)";
SqlCommand _Query = New SqlCommand(_state, myCnn);
_Query.Parameters.AddWithValue("#msg", msg);
_Query.Parameters.AddWithValue("#camID", camID);
_Query.Parameters.AddWithValue("#path", i`enter code here`mageFile`);
_Query.Parameters.AddWithValue("#filename", Name);
Try
{
myCnn.Open();
String checkname = (String)_Query.ExecuteScalar();
myCnn.Close();
getcheckname = checkname;
Console.WriteLine("OK");
}
Catch (Exception)
{
}
}
}

Categories

Resources