My function: Removes the unit in a specific row of a given Table
private static void removeUnits(String connectionString, String tableName, String columnID, String columnToFix)
{
List<String> rowsToEdit = new List<String>();
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (var command = connection.CreateCommand())
{
command.CommandText = "SELECT " + columnID + "," + columnToFix + " FROM " + tableName;
connection.Open();
using (var reader = command.ExecuteReader())
{
var indexOfR_MEASUREDVALUEID = reader.GetOrdinal(columnID);
var indexOfT_VALUE = reader.GetOrdinal(columnToFix);
while (reader.Read())
{
var t_value = reader.GetValue(indexOfT_VALUE);
var t_id = reader.GetValue(indexOfR_MEASUREDVALUEID);
String newValue = getWithoutUnit(t_value.ToString());
if (newValue != null)
{
String sql = "UPDATE " + tableName + " SET " + columnToFix + "='" +
newValue + "' WHERE " + columnID + "='" + t_id + "';";
rowsToEdit.Add(sql);
}
}
connection.Close();
}
}
Console.WriteLine("start writing " + rowsToEdit.Count + " entries?");
Console.ReadLine();
SqlCommand sqlCmd;
sqlCmd = new SqlCommand("", connection);
sqlCmd.Connection.Open();
foreach (String command in rowsToEdit)
{
sqlCmd.CommandText = command;
sqlCmd.ExecuteNonQuery();
}
}
Console.WriteLine(rowsToEdit.Count + " commands executed");
}
I am using C# in Visual Studio 2010 and SQL-Server 2012.
It works fine, but executing of 200000 lines takes really long.
Is its possible to do this faster?
My suggestion involves looking into parallelism:
Note: The code isn't tested, just typed it out in Notepad++
private static void removeUnits(String connectionString, String tableName, String columnID, String columnToFix)
{
List<new Tuple<object, object>> rowsToEdit = new List<new Tuple<object, object>>();
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (var command = connection.CreateCommand())
{
command.CommandText = "SELECT " + columnID + "," + columnToFix + " FROM " + tableName;
connection.Open();
using (var reader = command.ExecuteReader())
{
var indexOfR_MEASUREDVALUEID = reader.GetOrdinal(columnID);
var indexOfT_VALUE = reader.GetOrdinal(columnToFix);
while (reader.Read())
{
rowsToEdit.Add(new Tuple<object, object>(reader.GetValue(indexOfT_VALUE),reader.GetValue(indexOfR_MEASUREDVALUEID)));
}
connection.Close();
}
}
}
// Use parallelism here
Parallel.Foreach(rowsToEdit, currentRow =>
{
String newValue = getWithoutUnit(currentRow.Value1.ToString());
if (newValue != null)
{
// reopen connection
// use parameters here, and call SP
}
}
Console.WriteLine("start writing " + rowsToEdit.Count + " entries?");
Console.ReadLine();
}
Stored Proc:
Create StoredProcedure MySP
(
#tablename varchar(50),
#columnToFix varchar(50),
#newValue varchar(50),
#columnID varchar(50),
#tID varhcar(varchar(50)
)
As
Begin
Declare #MySQL varchar(500)
Set #MySQL = 'Update ' + #tableName + ' Set ' + #columnToFix + ' = '' + #newValue + ''' + ' Where ' + #columnID + ' = '' + #tID + '''
sp_executesql #MySQL
End
It's important to note that dynamic sql is generally frowned down upon. Here's a link discussing dynamic sql (pros/cons):http://www.sommarskog.se/dynamic_sql.html
Also it's possible you may run into some locking/contention issues b/c you're hitting one table(based on the input parameters of the function).
First try to use Parameters as already mentioned in the comments. Second, use the SqlCommand.Prepare() statement. The actual speed also depends on your machine capacities (HD Write Speed/RAM). Here is the example (you may have to edit the SqlDbTypes according to your Colum Types)
private static void RemoveUnits(string connectionString, string tableName, string columnID, string columnToFix)
{
Dictionary<int, string> rowsToEdit = new Dictionary<int, string>();
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT " + columnID + "," + columnToFix + " FROM " + tableName;
using (var reader = command.ExecuteReader())
{
var indexOfR_MEASUREDVALUEID = reader.GetOrdinal(columnID);
var indexOfT_VALUE = reader.GetOrdinal(columnToFix);
while (reader.Read())
{
string t_value = reader.GetString(indexOfT_VALUE);
int t_id = reader.GetInt32(indexOfR_MEASUREDVALUEID);
string newValue = getWithoutUnit(t_value);
if (newValue != null)
{
// save values in dictionary
rowsToEdit[t_id] = newValue;
}
}
}
}
Console.WriteLine("start writing " + rowsToEdit.Count + " entries?");
Console.ReadLine();
string updateCmd = "UPDATE " + tableName + " SET " + columnToFix + "= #Value WHERE " + columnID + "= #Key;";
using (SqlTransaction transaction = connection.BeginTransaction())
{
SqlCommand sqlCmd = connection.CreateCommand();
sqlCmd.CommandText = updateCmd;
sqlCmd.Parameters.Add("#Value", System.Data.SqlDbType.NVarChar, -1);
sqlCmd.Parameters.Add("#Key", System.Data.SqlDbType.Int);
// important for performance
sqlCmd.Prepare();
foreach (var update in rowsToEdit)
{
// change values of parameters
sqlCmd.Parameters["#Key"].Value = update.Key;
sqlCmd.Parameters["#Value"].Value = update.Value;
// and execute it
sqlCmd.ExecuteNonQuery();
}
transaction.Commit();
}
}
Console.WriteLine(rowsToEdit.Count + " commands executed");
}
Edit: if getWithoutUnit(string) does something not very complex, you could probably do your operation with a single statement using TSQL, which comes with various string manipulation capabilities. Like UPDATE TableName SET StringColumn = <string manipulation TSQL here>, see http://msdn.microsoft.com/en-us/library/ms181984.aspx
Edit2: added transaction from comment hint (indeed should be faster as well), strongly typed columns
Related
public static boolean CheckIsDataAlreadyInDBorNot(String TableName,
String dbfield, String fieldValue) {
SQLiteDatabase sqldb = EGLifeStyleApplication.sqLiteDatabase;
String Query = "Select * from " + TableName + " where " + dbfield + " = " + fieldValue;
Cursor cursor = sqldb.rawQuery(Query, null);
if(cursor.getCount() <= 0){
cursor.close();
return false;
}
cursor.close();
return true;
}
Im trying to update rows in my table using loop, I get no error but nothing changed in my data...Thats my code.. What am I missing ?
private void updateZipInDB(List<ZipObj> zipCodeToUpdate)
{
var comm = "";
string DbConnString = ConfigurationManager.AppSettings["dbConnectionString"].ToString();
using (SqlConnection conn = new SqlConnection(DbConnString))
{
comm = "UPDATE Account SET address1_postalcode = #newVal WHERE AccountId = #accountID";
using (SqlCommand command = new SqlCommand(comm, conn))
{
conn.Open();
command.Parameters.AddWithValue("#newVal", "f");
command.Parameters.AddWithValue("#accountID", "f");
for (int i = 0; i < zipCodeToUpdate.Count; i++)
{
zipCodeToUpdate[i].NewVal + "' WHERE AccountId = '" + zipCodeToUpdate[i].AccountId + "'";
command.Parameters["#newVal"].Value = zipCodeToUpdate[i].NewVal;
command.Parameters["#accountID"].Value = zipCodeToUpdate[i].AccountId;
command.ExecuteNonQuery();
}
conn.Close();
}
}
}
im getting data from the server as expected as you can see here (the data is not null)
but it won't enter to while (reader.Read())
or sometimes after one or two iteration im getting the exception
"Data is Null. This method or property cannot be called on Null values."
again, the data is not null
EDIT: added some code snippet
System.Data.SqlClient.SqlConnection sqlConnection = null;
try
{
sqlConnection = connectToDB();
SqlCommand cmd = new SqlCommand(#"SELECT TOP 50 R.[RoundID] ,[DailyOrder] ,min(R.[RoundName]) as RoundName, min([EquipCode]) as TruckCode,
sum(RD.[Weight]) as [Weight], RD.BlilCode, min(Blil.BlilName) as BlilName
FROM [CVfeedDB].[dbo].[Planning.Rounds] as R
left join [CVfeedDB].[dbo].[Planning.RoundsDetail] as RD on R.RoundID = RD.RoundID
left join [CVfeedDB].[dbo].[constants.Blil] as Blil on RD.BlilCode = Blil.BlilCode
WHERE R.[ActionDate] = #ActionDate
Group by R.[RoundID] ,[DailyOrder], RD.BlilCode
order by [DailyOrder] ", sqlConnection);
cmd.CommandType = System.Data.CommandType.Text;
//string date = Convert.ToString();
var dt = DateTime.ParseExact(Variables().Item("Date Select").get_Value(0).ToString(), "dd/MM/yyyy", null);
var dt1 = dt.Date.ToString("yyyy-MM-dd");
cmd.Parameters.AddWithValue("#ActionDate",dt1 );
string prefix = "";
int i = 1;
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
prefix = ordersName + i.ToString() + "]";
List<object> list = new List<object>();
List<object> IDList = new List<object>();
int id = Convert.ToInt32(Variables().Item(prefix + ".LoopID").get_Value(0));
int k = reader.GetInt32(0);
if (id == 0 || id == k)//if no id or we are writing the same id
{
Variables().Item(prefix + ".LoopID").set_Value(0, reader.GetInt32(0));
//Variables().Item(prefix + ".").set_Value(0, reader.GetInt32(1)); //Order sequence
Variables().Item(prefix + ".LoopName").set_Value(0, reader.GetString(2));
Variables().Item(prefix + ".Truck").set_Value(0, Convert.ToInt32(reader.GetString(3)));
Variables().Item(prefix + ".Weight").set_Value(0, Convert.ToInt32(reader.GetDecimal(4)));
Variables().Item(prefix + ".MixID").set_Value(0, Convert.ToInt32(reader.GetString(5)));
Variables().Item(prefix + ".MixName").set_Value(0, reader.GetString(6));
}
please not that Variables().Item(...) it how I communicate with 3rd party software
First problem is that your SqlConnection is null. It will always return null value.
Secondally
You should check the reader has rows like i m using reader.Hasrows
System.Data.SqlClient.SqlConnection sqlConnection = null;
try
{
sqlConnection = connectToDB();
SqlCommand cmd = new SqlCommand(#"SELECT TOP 50 R.[RoundID] ,[DailyOrder] ,min(R.[RoundName]) as RoundName, min([EquipCode]) as TruckCode,
sum(RD.[Weight]) as [Weight], RD.BlilCode, min(Blil.BlilName) as BlilName
FROM [CVfeedDB].[dbo].[Planning.Rounds] as R
left join [CVfeedDB].[dbo].[Planning.RoundsDetail] as RD on R.RoundID = RD.RoundID
left join [CVfeedDB].[dbo].[constants.Blil] as Blil on RD.BlilCode = Blil.BlilCode
WHERE R.[ActionDate] = #ActionDate
Group by R.[RoundID] ,[DailyOrder], RD.BlilCode
order by [DailyOrder] ", sqlConnection);
cmd.CommandType = System.Data.CommandType.Text;
//string date = Convert.ToString();
var dt = DateTime.ParseExact(Variables().Item("Date Select").get_Value(0).ToString(), "dd/MM/yyyy", null);
var dt1 = dt.Date.ToString("yyyy-MM-dd");
cmd.Parameters.AddWithValue("#ActionDate",dt1 );
string prefix = "";
int i = 1;
SqlDataReader reader = cmd.ExecuteReader();
if(reader.HasRows)
{
while (reader.Read())
{
prefix = ordersName + i.ToString() + "]";
List<object> list = new List<object>();
List<object> IDList = new List<object>();
int id = Convert.ToInt32(Variables().Item(prefix + ".LoopID").get_Value(0));
int k = reader.GetInt32(0);
if (id == 0 || id == k)//if no id or we are writing the same id
{
Variables().Item(prefix + ".LoopID").set_Value(0, reader.GetInt32(0));
//Variables().Item(prefix + ".").set_Value(0, reader.GetInt32(1)); //Order sequence
Variables().Item(prefix + ".LoopName").set_Value(0, reader.GetString(2));
Variables().Item(prefix + ".Truck").set_Value(0, Convert.ToInt32(reader.GetString(3)));
Variables().Item(prefix + ".Weight").set_Value(0, Convert.ToInt32(reader.GetDecimal(4)));
Variables().Item(prefix + ".MixID").set_Value(0, Convert.ToInt32(reader.GetString(5)));
Variables().Item(prefix + ".MixName").set_Value(0, reader.GetString(6));
}
}
}
try this.
string namethestore = myReader.IsDBNull(namePos)
? string.Empty
: reader.GetString(reader.GetString(2));
Variables().Item(prefix + ".LoopName").set_Value(0, namethestore);
I have added isNull(rowname, 0 ) to the problematic rows and it solved my problem
I'm having issue with creating product code in recursion.
What I want to do is:
I enter code 1000
-If code exist in database regenerateCode(string code)
-else insert into database
Code:
(...)
if(codeExist)
CodeTB.Text = regenerateCode(string toParse); //toParse = 1000
string regenerateCode(string toParse)
{
string helper = "";
int parseCode = int.Parse(toParse);
helper = new string('0', 4 - parseCode.ToString().Length);
helper += parseCode + 1;
using (SqlConnection conn = new SqlConnection(cString.c_String))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("SELECT Product.productID FROM Product " +
"WHERE Product.PLU = '" + helper + "' ", conn))
{
using (SqlDataReader rdr = cmd.ExecuteReader())
{
if (rdr.HasRows)
{
// if code still exist in database, regenerate it
regenerateCode(helper);
}
else
{
//else return code
return helper;
}
}
}
}
return helper;
}
Actually it works fine with example:
1000 (exist)
1001 (exist)
1002 (not exist, insert), but
when code = 1002, it goes into line with else {return helper;} and have no idea why going again to regenerateCode() method..
Any ideas?
It happens because you do nothing with the return value. You pass helper to the recursion, but do not place the return value anywhere. your method should look like this:
string regenerateCode(string toParse)
{
string helper = "";
int parseCode = int.Parse(toParse);
helper = new string('0', 4 - parseCode.ToString().Length);
helper += parseCode + 1;
using (SqlConnection conn = new SqlConnection(cString.c_String))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("SELECT Product.productID FROM Product " +
"WHERE Product.PLU = '" + helper + "' ", conn))
{
using (SqlDataReader rdr = cmd.ExecuteReader())
{
// Return the next code that doesn't exist
return rdr.HasRows ? regenerateCode(helper) : helper;
}
}
}
}
Also, remember that while string are reference types, they are immutable. which means that a string that is passed as an argument would not change like a normal array. see: How are strings passed in .NET?
I'm having a lot of errors can't open connect etc. I use VS 2010 c# wpf
String str;
SqlConnection myConn = new SqlConnection("Server=localhost;Integrated security=SSPI;database=master");
str = " CREATE DATABASE "
+ " ON PRIMARY "
+ " (NAME = " + "MyDatabase_Data" + ", "
+ " FILENAME = '" + "C:\\MyDatabaseData.mdf" + "', "
+ " SIZE = 2MB,"
+ " FILEGROWTH =" + "10%" + ") "
+ " LOG ON (NAME =" + "MyDatabase_Log" + ", "
+ " FILENAME = '" + "C:\\MyDatabaseLog.ldf" + "', "
+ " SIZE = 1MB, "
+ " FILEGROWTH =" + "10%" + ") ";
SqlCommand myCommand = new SqlCommand(str, myConn);
try
{
myConn.Open();
myCommand.ExecuteNonQuery();
MessageBox.Show("DataBase is Created Successfully", "MyProgram", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (System.Exception ex)
{
MessageBox.Show(ex.ToString(), "MyProgram", MessageBoxButton.OK, MessageBoxImage.Information);
}
finally
{
if (myConn.State == ConnectionState.Open)
{
myConn.Close();
}
}
Add the following references:
c:\Program Files\Microsoft SQL
Server\100\SDK\Assemblies\Microsoft.SqlServer.Smo.dll
C:\Program Files (x86)\Microsoft SQL Server\100\SDK\Assemblies\Microsoft.SqlServer.Management.Sdk.Sfc.dll
c:\Program Files\Microsoft SQL
Server\100\SDK\Assemblies\Microsoft.SqlServer.ConnectionInfo.dll
In App config please inser the following fragment
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0"/>
</startup>
The code:
var myConn = "Server=localhost;Integrated security=SSPI;database=master";
//The CREATE DATABASE statement failed. The primary file must be at least 3 MB to accommodate a copy of the model database.
var command = #"
CREATE DATABASE myDB
ON PRIMARY
(
NAME = MyDatabaseData,
FILENAME = 'C:\Temp\MyDatabaseData.mdf',
SIZE = 3MB,
FILEGROWTH =10%
)
LOG ON
(
NAME =MyDatabaseLog,
FILENAME = 'C:\Temp\MyDatabaseLog.ldf',
SIZE = 1MB,
FILEGROWTH =10%
)";
using (var conn = new SqlConnection(myConn))
{
try
{
var server = new Server(new ServerConnection(conn));
server.ConnectionContext.ExecuteNonQuery(command);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}