Update SQL table very slow - sql

I have problem when I try to update SQL table with
I have datagridview and I need to update SQL table and take the value form my datagridview . my datagridview have more than 10000 rows
I take time more than 1:30 hour very slow
datagridview name "dgv_balance"
Here is the code:
using (SqlConnection cn = new SqlConnection())
{
cn.ConnectionString = "My Connection"
cn.Open();
using (SqlCommand cmd_select = new SqlCommand())
{
for (int i = 0; i < dgv_balance.RowCount; i++)
{
cmd_select.Connection = cn;
cmd_select.CommandType = CommandType.StoredProcedure;
cmd_select.CommandText = "clients_balances_select_glid_date";
cmd_select.Parameters.AddWithValue("#glid", Convert.ToString(dgv_balance.Rows[i].Cells[0].Value));
cmd_select.Parameters.AddWithValue("#date", Convert.ToDateTime(dgv_balance.Rows[i].Cells[2].Value));
if (cmd_select.ExecuteScalar().ToString()=="")
{
using (SqlCommand cmd_insert = new SqlCommand())
{
cmd_insert.Connection = cn;
cmd_insert.CommandType = CommandType.StoredProcedure;
cmd_insert.CommandText = "clients_balances_insert_data";
cmd_insert.Parameters.AddWithValue("#glid", Convert.ToString(dgv_balance.Rows[i].Cells[0].Value));
cmd_insert.Parameters.AddWithValue("#name", Convert.ToString(dgv_balance.Rows[i].Cells[1].Value));
cmd_insert.Parameters.AddWithValue("#date", Convert.ToString(dgv_balance.Rows[i].Cells[2].Value));
cmd_insert.Parameters.AddWithValue("#balance", Convert.ToString(dgv_balance.Rows[i].Cells[3].Value));
cmd_insert.ExecuteNonQuery();
cmd_insert.Parameters.Clear();
}
}
else
{
using (SqlCommand cmd_update= new SqlCommand())
{
cmd_update.Connection = cn;
cmd_update.CommandType = CommandType.StoredProcedure;
cmd_update.CommandText = "clients_balances_update_balance";
cmd_update.Parameters.AddWithValue("#glid", Convert.ToString(dgv_balance.Rows[i].Cells[0].Value));
cmd_update.Parameters.AddWithValue("#date", Convert.ToString(dgv_balance.Rows[i].Cells[2].Value));
cmd_update.Parameters.AddWithValue("#balance", Convert.ToString(dgv_balance.Rows[i].Cells[3].Value));
cmd_update.ExecuteNonQuery();
cmd_update.Parameters.Clear();
}
}
cmd_select.Parameters.Clear();
}
}
}

You may have to call SELECT command for one time only before you loop through your datagridview rows and cache the result data and check on the result while iterating your datagridview instead of calling it on each row. This way you will reduce your commands by 10000.
It also better if you could show us your procedures' queries.
Or if your datagridview is the ONLY source for your data then you can delete all your previous data in your database and make one insert call for all of your datagridview data.
Try this:
using (SqlConnection cn = new SqlConnection())
{
cn.ConnectionString = "MyConnection" ;
cn.Open();
SqlDataAdapter da = new SqlDataAdapter();
DataTable dt = new DataTable();
using (SqlCommand cmd_select = new SqlCommand())
{
cmd_select.Connection = cn; cmd_select.CommandType = CommandType.StoredProcedure; cmd_select.CommandText = "clients_balances_select_glid_date";
da.SelectCommand = cmd_select;
da.Fill(dt);
for (int i = 0; i < dgv_balance.RowCount; i++)
{
if(/* check here if dt contains this row*/)
{
// Insert
}
else
{
// Update
}
}
}
}

I think you should insert or update all data one time.
Create index for glId column. If glId is primary key, it's indexed.
Assumes that List ClientBalance is list items you need update or insert.
public class ClientBalance
{
GlId int {get;set;}
ClientName string {get;set;}
Balance decimal {get;set;}
DateInput DateTime {get;set;}
}
You could serialize list Item to xml string and pass it to store procedure
public string Serialize<T>(T value) where T : new()
{
var serializeXml = string.Empty;
if (value != null)
{
try
{
var xmlserializer = new XmlSerializer(typeof(T));
var stringWriter = new StringWriter();
var writer = XmlWriter.Create(stringWriter);
xmlserializer.Serialize(writer, value);
serializeXml = stringWriter.ToString();
writer.Close();
}
catch (Exception ex)
{
return string.Empty;
}
}
return serializeXml;
}
Create a new store procedure for insert or update item like that:
CREATE PROCEDURE [dbo].[clients_balances_insert_or_update]
(
#xmlObject nvarchar(max)
)
AS
BEGIN
-- TABLE INCLUDE DATE FROM XML
DECLARE #tblBalances AS TABLE
(
GlId int,
DateInput datetime,
ClientName nvarchar(50),
Balance decimal(18,2)
)
DECLARE #idoc int -- xml id
-- PARSE XML TO OBJECT
EXEC sp_xml_preparedocument #idoc OUTPUT, #xmlObject
INSERT INTO #tblBalances
(
GlId, DateInput, ClientName, Balance
)
SELECT s.GlId, s.DateInput, s.ClientName, s.Balance
FROM OPENXML (#idoc, '/ArrayOfClientBalance/ClientBalance', 8) WITH (
GlId int 'GlId',
DateInput datetime 'DateInput',
ClientName NVARCHAR(50) 'ClientName',
Balance DECIMAL(18,2) 'Balance'
) s
EXEC sp_xml_removedocument #idoc
-- USE MERGE FOR INSERT OR UPDATE DATE
-- Use transaction
BEGIN TRAN InsertOrUpdate
BEGIN TRY
MERGE Target AS T
USING #tblBalances AS S
ON (T.GlId = S.GlId)
WHEN NOT MATCHED BY TARGET
THEN INSERT( GlId, DateInput, ClientName, Balance) VALUES( GlId, DateInput, ClientName, Balance)
WHEN MATCHED
THEN UPDATE SET DateInput = S.DateInput, Balance = s.Balance
COMMIT TRAN InsertOrUpdate;
END TRY
BEGIN CATCH
ROLLBACK TRAN InsertOrUpdate;
THROW;
END CATCH
END
Hope this helpfully!

Related

System.Data.SqlClient.SqlException thrown after Attempted Execution of a Procedure

I am making a straightforward application using AngularJS and ASP.NET, which I am fairly new to. I created an SQL procedure but every time I have it executed, it throws the following error:
System.Data.SqlClient.SqlException: 'Procedure or function 'LoginProc'
expects parameter '#IsValid', which was not supplied.'
How do I resolve this exception? Here is the code for storing the procedure:
ALTER PROCEDURE LoginProc
#username VARCHAR(50),
#password VARCHAR(MAX),
#IsValid bit out
AS
BEGIN
SET #IsValid=(SELECT COUNT(username) from "User" WHERE username=N'#username' and password=N'#password')
END
And here is the code that attempts to execute the procedure:
public class db
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings
["dbconnect"].ConnectionString);
public int userlogin(User user)
{
int res;
SqlCommand cmd = new SqlCommand("LoginProc", con);
cmd.CommandType = CommandType.StoredProcedure;
if (user.username != null && user.password != null) {
cmd.Parameters.AddWithValue("#username", user.username);
cmd.Parameters.AddWithValue("#password", user.password);
SqlParameter oblogin = new SqlParameter();
oblogin.ParameterName = "#IsVaild";
oblogin.Direction = ParameterDirection.Output;
oblogin.SqlDbType = SqlDbType.Bit;
cmd.Parameters.Add(oblogin);
con.Open();
cmd.ExecuteNonQuery();
res = Convert.ToInt32(oblogin.Value);
con.Close();
}
else
{
res = 0;
}
return res;
}
}
You have just mispelled #IsValid here:
oblogin.ParameterName = "#IsVaild";

SQL Server DataAdapter is not filling datatable

I am running code to fill a dataset from a SQL Server table, but for some reason it is not filling the datatable. I have run the stored procedure with the values when stepping through the code and it returns rows. I have checked via SQL Server Profiler what command runs and then executed the same command through SQL Server Management Studio and it returns rows, but for some reason in Visual Studio it returns no rows, yet it is not returning any exception.
The code is :
try
{
using (SqlConnection cnn = new SqlConnection(ConfigurationManager.ConnectionStrings["Intranet"].ConnectionString))
{
switch (command)
{
case "radiobutton":
string school = ParameterString[0];
using (SqlDataAdapter da = new SqlDataAdapter(GET_TEMPLATE_NAMES, cnn))
{
DataTable dt = new DataTable();
da.SelectCommand.CommandType = CommandType.StoredProcedure;
da.SelectCommand.Parameters.AddWithValue("#TemplateforSchool", school);
cnn.Open();
da.Fill(dt);
lstTemplates.DataSource = dt;
lstTemplates.DataBind();
}
break;
case "listbox": // If the listbox triggers the callback then update the grid
switch (radSchools.SelectedItem.Text)
{
case "Junior School":
StartYear = 1;
EndYear = 5;
break;
case "Middle School":
StartYear = 6;
EndYear = 8;
break;
case "Senior School":
StartYear = 9;
EndYear = 12;
break;
}
string TemplateName = ParameterString[0];
int DetentionCount = Convert.ToInt16(ParameterString[1]);
string DetentionType = ParameterString[2];
using (SqlDataAdapter da = new SqlDataAdapter(GET_CAREGIVER_EMAIL_LIST, cnn))
{
DataTable dt = new DataTable();
da.SelectCommand.CommandType = CommandType.StoredProcedure;
da.SelectCommand.Parameters.Add(new SqlParameter
{
ParameterName = "#DetentionType",
SqlDbType = SqlDbType.VarChar,
Value= DetentionType
});
da.SelectCommand.Parameters.Add(new SqlParameter
{
ParameterName="#DetentionCounter",
SqlDbType=SqlDbType.Int,
Value=DetentionCount
});
da.SelectCommand.Parameters.Add(new SqlParameter
{
ParameterName = "#StartYear",
SqlDbType = SqlDbType.Int,
Value = StartYear
});
da.SelectCommand.Parameters.Add(new SqlParameter
{
ParameterName = "#EndYear",
SqlDbType = SqlDbType.Int,
Value = EndYear
});
cnn.Open();
da.Fill(dt);
gdvCaregiverEmailList.DataSource = dt;
gdvCaregiverEmailList.DataBind();
}
break;
}
}
}
catch(Exception ex)
{
}
The problem is in the listbox: section of the switch statement. The SqlDataAdapter works fine in the radio button section of the switch.
I am not sure what I am missing so any help would be much appreciated.
I have checked SqlDataAdapter does not fill DataSet and also SqlDataAdapter not filling DataTable but the first was not relevant to my situation and the second had no accepted answer that I could find.
The SQL Server stored procedure that I am calling is
ALTER PROCEDURE [dbo].[GetCaregiverEmailList]
#DetentionType CHAR(2),
#DetentionCounter INT,
#StartYear INT,
#EndYear INT
AS
BEGIN
SELECT DISTINCT
sdc.StudentCode, s.Student#, s.GIVEN_NAME, s.SURNAME,
sdc.DetentionCount, sdc.DetentionType,
s.GIVEN_NAME + ' ' + s.SURNAME AS FullName,
LTRIM(s.CURRENT_YEAR) AS CurrentYear,
i.EMAIL_HOME, RTRIM(i.SALUTATION) AS EmailTitle,
ax.CORR_PREFERENCE, ar.CAREGIVER_NO
FROM
StudentDetentionCounter sdc
LEFT JOIN
[PCSchool].[dbo].[Student] s ON sdc.StudentCode = s.STUDENT#
INNER JOIN
[PCSchool].[dbo].[ALUMREL] ar ON sdc.StudentCode = ar.CHILD#
LEFT JOIN
[PCSchool].[dbo].[IDENTITY] i ON ar.PARENT# = i.[MEMBER#]
LEFT JOIN
[PCSchool].[dbo].[ALUMREL_EX] ax ON ar.parent# = ax.PARENT#
WHERE
(ar.PARENT# <> ar.FAMILY_HASH)
AND ar.EN_EMAIL IN ('I','A')
AND (ax.CORR_PREFERENCE = 1)
AND (sdc.DetentionCount = #DetentionCounter
AND sdc.DetentionType = #DetentionType)
AND (CONVERT(INT, (LTRIM(s.CURRENT_YEAR))) BETWEEN #StartYear AND #EndYear)
ORDER BY
s.SURNAME
END
The command that is executed when I look at SQL Server Profiler is
exec GetCaregiverEmailList #DetentionType='LT',#DetentionCounter=3,#StartYear=9,#EndYear=12
And the following are the rows that are returned if I execute the stored procedure manually or running the above exec command.
Any suggestions or help would be much appreciated.
Regards,
Darren

No overload for method 'TryParse' takes '1' arguments

Actually im trying to insert as well as update data into datagridview at run time for that i have written one code but while executing it give me Data type No overload for method 'TryParse' takes '1' arguments
my accdb table structure is like below
Field Datatype
Account-- Memo
AccountNumber--Number
Date--Date/Time
Description--Memo
Post_Ref--Memo
Debit--Number
Credit--Number
Balance--Number
**
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
string connectionString = null;
connectionString = ConfigurationManager.ConnectionStrings["AccessConnectionString"].ConnectionString;
con.ConnectionString = connectionString;
string cmd1 = "insert into Ledger([AccountNumber],[Account],[Date],[Description],[Post_Ref],[Debit],[Credit],[Balance])values(?,?,?,?,?,?,?,?)";
OleDbCommand cmd = new OleDbCommand(cmd1, con);
con.Open();
cmd.CommandType = CommandType.Text;
int accountNumber;
bool accountHasValue = int.TryParse(dataGridView1.Rows[e.RowIndex].Cells["AccountNumber"].Value.ToString(), out accountNumber);
if (accountHasValue)
{
cmd.Parameters.AddWithValue("#AccountNumber", accountNumber);
}
string accounts = dataGridView1.Rows[e.RowIndex].Cells["Account"].Value.ToString();
cmd.Parameters.AddWithValue("#Account", accounts);
DateTime datetime;
bool dateTimeHasValue = DateTime.TryParse(dataGridView1.Rows[e.RowIndex].Cells["Date"].Value.ToString(), out datetime);
if (dateTimeHasValue)
{
cmd.Parameters.AddWithValue("#Date", datetime);
}
string Description = dataGridView1.Rows[e.RowIndex].Cells["Description"].Value.ToString();
cmd.Parameters.AddWithValue("#Description", Description);
string Post_Ref = dataGridView1.Rows[e.RowIndex].Cells["Post_Ref"].Value.ToString();
cmd.Parameters.AddWithValue("#Post_Ref", Post_Ref);
int debit;
bool debitHasValue = Int32.TryParse(dataGridView1.Rows[e.RowIndex].Cells["Debit"].Value.ToString(), out debit);
if (debitHasValue)
{
cmd.Parameters.AddWithValue("#Debit", debit);
}
int Credits;
bool CreditsHasValue = Int32.TryParse(dataGridView1.Rows[e.RowIndex].Cells["Credit"].Value.ToString(), out Credits);
if (CreditsHasValue)
{
cmd.Parameters.AddWithValue("#Credit", Credits);
}
int Balances;
bool BalancesHasValue = Int32.TryParse(dataGridView1.Rows[e.RowIndex].Cells["Balance"].Value.ToString(), out Balances);
if (BalancesHasValue)
{
cmd.Parameters.AddWithValue("#Balance", Balances);
}
cmd.ExecuteNonQuery();
con.Close();
Load_data();
}
The error simply means the TryParse method does not have an overload that accepts one parameter. If you look at the documentation, it takes two parameters.
For the lines of code that use TryParse, first declare a variable and use it as out parameter and pass it for seeding your database. Show me the code !!! Ok, see examples below.
//For accountNumber
int accountNumber;
bool accountHasValue = int.TryParse(dataGridView1.Rows[e.RowIndex].Cells["AccountNumber"].Value, out accountNumber);
if(accountHasValue)
{
cmd.Parameters.AddWithValue("#AccountNumber", accountNumber);
}
//For Datetime
DateTime datetime;
bool dateTimeHasValue = DateTime.TryParse(dataGridView1.Rows[e.RowIndex].Cells["Date"].Value, out datetime);
if(dateTimeHasValue)
{
cmd.Parameters.AddWithValue("#Date", datetime);
}
//For Debit
int debit;
bool debitHasValue = Int32.TryParse(dataGridView1.Rows[e.RowIndex].Cells["Debit"].Value, debit);
if(debitHasValue )
{
cmd.Parameters.AddWithValue("#Debit", debit);
}
Basically all lines of code that you use the TryParse, implement them as above.

how do i call a sql function from my asp.net project?

This is my function:
create function fn_Inventory(#qty int, #item_ID int)
returns int
as begin
declare #result int
set #result = (SELECT Quantity - #qty from Items where #item_ID = item_ID)
return #result
end
And I want to execute this function from my asp.net code; how to do it?
public int TotalCupom(int qty,int item_ID)
{
int result;
SqlDataAdapter da2 = new SqlDataAdapter();
if (conex1.State == ConnectionState.Closed)
{ conex1.Open();}
SqlCommand Totalf = new SqlCommand("SELECT dbo.fn_Inventory(#qty,#item_ID)", qty,item_ID);
SqlParameter _qty= new SqlParameter("#qty", SqlDbType.Int);
SqlParameter _item_ID= new SqlParameter("#item_ID", SqlDbType.Int);
_qty.Value = qty;
_item_ID.Value = item_ID;
result= Totalf.ExecuteScalar();
return result;
}

Sending parameters to a stored procedure

Where is the problem in my code?
I use a stored procedure and transaction.
For one parameter to be working properly, but when the number of parameters is more than one error occurs.
Where is my problem?
This is my code in C#
internal static bool ExecuteNonQueryTransaction(string CommandName, CommandType cmdType, SqlParameter[][] pars)
{
int result = 0;
SqlTransaction tr = null;
int h = pars.GetLength(0);
using (SqlConnection con = new SqlConnection(CONNECTION_STRING))
{
if (con.State != ConnectionState.Open)
{
con.Open();
}
try
{
tr = con.BeginTransaction();
using (SqlCommand cmd = con.CreateCommand())
{
cmd.CommandType = cmdType;
cmd.Transaction = tr;
cmd.CommandText = CommandName;
// cmd.Parameters.AddRange(pars);
for (int i = 0; i < pars.GetLength(0); i++)
{
cmd.Parameters.AddRange(pars[i]);
cmd.ExecuteNonQuery();
}
tr.Commit();
}
}
catch
{
if (tr != null)
{
tr.Rollback();
}
//return false;
}
}
return (result > 0);
}
and this my stored procedure
ALTER PROCEDURE dbo.AddNewUserTypePageAccess
(#id_user_type int,
#id_page_access int)
as
insert into user_type_page_access(id_user_type, id_page_access)
values(#id_user_type, #id_page_access)
return
Thank you for your help.....
You shouldn't call ExecuteNonQuery(); inside the loop that adds the parameters! Add all parameters, and then call ExecuteNonQuery(); once, with all the parameters in place.
Use this code:
using (SqlCommand cmd = con.CreateCommand())
{
cmd.CommandType = cmdType;
cmd.Transaction = tr;
cmd.CommandText = CommandName;
// cmd.Parameters.AddRange(pars);
for (int i = 0; i < pars.GetLength(0); i++)
{
cmd.Parameters.AddRange(pars[i]);
}
// call ExecuteNonQuery only AFTER you've added all the parameters!
cmd.ExecuteNonQuery();
tr.Commit();
}