I have a table with a (IDcolumn, int), (Differencecolumn, int) and (Datecolumn DateTime) that contains different dates.
And a method that compute the difference between the dates that ignores the weekends.
public static double GetBusinessDays(DateTime startD, DateTime endD)
{
double calcBusinessDays =
1 + ((endD - startD).TotalDays * 5 -
(startD.DayOfWeek - endD.DayOfWeek) * 2) / 7;
if ((int)endD.DayOfWeek == 6) calcBusinessDays--;
if ((int)startD.DayOfWeek == 0) calcBusinessDays--;
return calcBusinessDays;
}
I want to get each GetBusinessDays value on each Datecolumn from date today.
And insert it to each corresponding Differencecolumn.
For example
ID Date Difference
1 4-22-2013
2 4-23-2013
3 4-24-2013
Assume that the date today is 4-28-2013. The difference must contain 6, 5, 4 respectively.
This what i have done for now but it not works :(
myDatabaseConnection.OpenConnection();
mySqlCommand.CommandType = CommandType.Text;
mySqlCommand.CommandText = "select * from Table1 where Difference IS Null";
SqlDataReader sqlreader = mySqlCommand2.ExecuteReader();
int i;
while (sqlreader.Read())
{
i = sqlreader.GetInt32(0);
double y = GetBusinessDays(sqlreader.GetDateTime(1), DateTime.Now);
string commandtext = "Update Table1 SET Difference = " + y + " Where ID = " + i + " ";
mySqlCommand.CommandText = " " + commandtext + " ";
}
myDatabaseConnection.CloseConnection();
First and foremost, you appear to be missing a call to mySqlCommand.ExecuteNonQuery(). That should go inside your while loop, after you assign to mySqlCommand.CommandText.
You'll also need to use a separate SqlCommand object for the Update query, as the existing one is being used by the SqlDataReader as you iterate through the result set. I also recommend always using parameterized SQL. Putting these two points together:
SqlCommand myUpdateCmd = new SqlCommand("Update [Table1] SET [Difference] = #Difference Where [ID] = #ID", myDatabaseConnection);
myUpdateCmd.Parameters.AddWithValue("#ID", i);
myUpdateCmd.Parameters.AddWithValue("#Difference", (int)y);
myUpdateCmd.ExecuteNonQuery();
Beyond that, here are some suggestions that you may find helpful:
You seem to be assuming that the Difference column will initially be NULL, but you didn't show the exact definition for Table1. Make sure the Difference column allows NULL values, and that there is no default value set (or that the default value is NULL).
To guarantee that the columns are in the order you expect, I recommend doing one of the following.
Specify the column names in your select query:
select [id], [date], [difference] from [Table1] where [difference] is null
When retrieving a column's value through the SqlDataReader, don't hard-code the column's ordinal (0, 1, 2, ...). Instead, use the GetOrdinal() method to dynamically determine the column's ordinal. For example:
i = sqlreader.GetInt32(sqlreader.GetOrdinal("id"));
Almost all of these ADO.NET objects are IDisposable. As such, it's generally best to make use of C#'s using statement to guarantee that these objects will be cleaned up.
using (SqlConnection myDatabaseConnection = new SqlConnection(myConnectionString))
{
// code that uses myDatabaseConnection goes here
}
Putting all of these points together, we end up with:
using (SqlConnection myDatabaseConnection = new SqlConnection("DB connection string goes here"))
{
myDatabaseConnection.Open();
using (SqlCommand mySqlCommand = new SqlCommand("select [id], [difference], [date] from [Table1] where [difference] is null", myDatabaseConnection))
using (SqlDataReader sqlreader = mySqlCommand.ExecuteReader())
using (SqlCommand myUpdateCmd = new SqlCommand("update [Table1] set [difference] = #difference where [id] = #id", myDatabaseConnection))
{
int i;
myUpdateCmd.Parameters.Add("#id", SqlDbType.Int);
myUpdateCmd.Parameters.Add("#difference", SqlDbType.Int);
while (sqlreader.Read())
{
i = sqlreader.GetInt32(sqlreader.GetOrdinal("id"));
double y = GetBusinessDays(sqlreader.GetDateTime(sqlreader.GetOrdinal("date")), DateTime.Now);
myUpdateCmd.Parameters["#id"].Value = i;
myUpdateCmd.Parameters["#difference"].Value = (int)y;
myUpdateCmd.ExecuteNonQuery();
}
}
}
Update: Karlx mentioned that he had to enable Multiple Active Result Sets on the database connection before his application would work. To do this, add "MultipleActiveResultSets=True" to your database connection string.
Related
I am letting the user able to delete a specific record in a SQL table. The problem is that I want to set the id(automatically) to the last id sequence presented into the db after the deletion. ex(delete item 14,when I add another item the id of that item won't be 15 but 14 because after the delete I've reset the id to 13 which is the last one after the delete)
private void btnCanc_Click(object sender, RoutedEventArgs e)
{
sqliteCon.Open();
try
{
string Test = null;//estrazione1
SqlCommand q = new SqlCommand("DELETE FROM tabSE WHERE idSE =" + txtIDL.Text.ToString(), sqliteCon);
//string q = "DELETE FROM tabSE WHERE idSE =" + txtIDL.Text.ToString();
SqlCommand q1 = new SqlCommand("DELETE FROM tabL WHERE idL =" + txtIDL.Text.ToString(), sqliteCon);
//string q1 = "DELETE FROM tabL WHERE idL =" + txtIDL.Text.ToString();
SqlCommand q2 = new SqlCommand("DELETE FROM tabSD WHERE id =" + txtIDL.Text.ToString(), sqliteCon);
//string q2 = "DELETE FROM tabSD WHERE id =" + txtIDL.Text.ToString();
q.ExecuteNonQuery();
q1.ExecuteNonQuery();
q2.ExecuteNonQuery();
SqlCommand m = new SqlCommand("SELECT idL FROm tabL", sqliteCon);
SqlDataReader idLRdr = null;//estrazione2
idLRdr = m.ExecuteReader();//estrazione3
while (idLRdr.Read())//estrazione4
{
Test = idLRdr["idL"].ToString();//estrazione5
}
SqlCommand r = new SqlCommand("DBCC CHECKIDENT(tabL,tabSE,tabSD,RESEED,'" + Test + "')", sqliteCon);
r.ExecuteNonQuery();
SqlCommand r1 = new SqlCommand("DBCC CHECKIDENT(tabL,RESEED,'" + Test + "')", sqliteCon);
r1.ExecuteNonQuery();
SqlCommand r2 = new SqlCommand("DBCC CHECKIDENT(tabSE,RESEED,'" + Test + "')", sqliteCon);
r2.ExecuteNonQuery();
SqlCommand r3 = new SqlCommand("DBCC CHECKIDENT(tabSD,RESEED,'" + Test + "')", sqliteCon);
r3.ExecuteNonQuery();
}
catch (SqlException ex)
{
MessageBox.Show(ex.Message);
}
MessageBox.Show("Dato Cancellato Correttamente");
sqliteCon.Close();
}
code improved but it update the value of the id of the table but not the real id of each table(idL,idSE,id)(those are my custom ids)
OK I'VE MADE MY TESTS,THE PROBLEM IS THAT THE ID'S OF EACH TABLE(idL(TABLE tabL),idSE(TABLE tabSE),id(TABLE tabSD))AREN'T UPDATED BY MY CODE DBCC WHILE THE ID'S OF EACH TABLE(THOSE WHICH AREN'T CUSTOM MADE) ARE UPDATE AUTOMATICALLY... I NEED TO UPDATE idL,idSE,id
Of course the first problem is the fact that you don't execute the commands, but there are a lot of things that could be improved in your code. First and foremost is the concatenation of strings to build a sql command. This leads to problems with parsing and to the dangerous Sql Injection trick used to hack a databases. I have changed your code to use a parameter and avoid these problems.
The second improvement is given by the ability to execute batch commands. In other words you can put all your command texts in a single string and separate each one using a semicolon. Then just execute the command only one time and everything will be executed by the database engine.
But the real problem in your code is the DBCC CheckIdentity RESEED part. This part requires you to know which value to set as the new Identity because the RESEED option without a new value works only if the next identity value is lower than the current max value in the IDENTITY column, moreover this could be done safely only if you have exclusive access to the database (I mean, none is adding records to these tables while you get the MAX value for the ID)
sqliteCon.Open();
try
{
string sqlText = #"DELETE FROM tabStoreExec WHERE idSE = #idse;
DELETE FROM tabList WHERE idL = #idse;
DELETE FROM tabStoricoDetail WHERE id = #idse";
SqlCommand q = new SqlCommand(sqlText, sqliteCon);
q.Parameters.Add("#idse", SqlDbType.Int).Value = Convert.ToInt32(txtIDL.Text);
q.ExecuteNonQuery();
// This is the point where you change the identity.
// To minimize concurrency problems we execute a stored procedure instead
sqlText = "ResetIdentity";
q.CommandText = sqlText;
q.CommandType = CommandType.StoredProcedure;
q.Parameters.Clear();
q.ExecuteNonQuery();
MessageBox.Show("Dato Cancellato Correttamente");
}
catch (SqlException ex)
{
MessageBox.Show(ex.Message);
}
sqliteCon.Close();
This is the possible code for your stored procedure, note that I don't know what is the name of the IDENTITY column in your tables. For this example I have used always id as the name for the IDENTITY column
create procedure ResetIdentity
as
begin
declare #maxval integer
set #maxval = (select MAX(id) from tabStoreExec);
dbcc checkident('tabStoreExec', RESEED, #maxval);
set #maxval = (select MAX(id) from tabStoricoDetail);
dbcc checkident('tabStoricoDetail', RESEED, #maxval);
set #maxval = (select MAX(id) from tabList);
dbcc checkident('tabList', RESEED, #maxval);
end
There is another improvement to your code and it is related to the using statement to create disposable objects like the database connection. The correct usage of such objects should be something like this
using(SqlConnection sqlConn = new SqlConnection(......))
{
sqlConn.Open();
.... do you database code here ....
} // This will close and dispose the connection
i will go as well with what #Steve said , the ID here is for the table (PK,FK)relation , why don't just add another field of sequential numbers that you update using LINQ as desired . and also your code is missing the query execution command ,
SqlCommand q = new SqlCommand("DELETE FROM tabStoreExec WHERE idSE =" +
txtIDL.Text.ToString(), sqliteCon);
//string q = "DELETE FROM tabStoreExec WHERE idSE =" + txtIDL.Text.ToString();
q.ExecuteNonQuery();
OR
con.Open();
using (SqlCommand q= new SqlCommand("DELETE FROM tabStoreExec WHERE idSE =" + txtIDL.Text.ToString(), sqliteCon))
{
q.ExecuteNonQuery();
}
con.Close();
I am fetching a column from database of char(2) data type.
On an Event, I am changing the char data type to int and incrementing it by 1, with this code:
int i = 0;
using (SqlConnection sqlCon = new SqlConnection(Login.connectionString))
{
string commandString = "SELECT MAX(CAST(Category_Code as INT)) FROM Category;";
SqlCommand sqlCmd = new SqlCommand(commandString, sqlCon);
sqlCon.Open();
SqlDataReader dr = sqlCmd.ExecuteReader();
while (dr.Read())
{
i = 1;
if (dr[0] == null)
{
Ctgry_CtgryCodeCb.Text = "1";
}
else
{
int cat_next_code = int.Parse(dr[0].ToString());
Ctgry_CtgryCodeCb.Text = (cat_next_code + 1).ToString();
}
}
}
It is working properly but not for the first time (doesn't add 1 to empty or 0) as column is empty.It shows some error that it is not is correct format to convert. I also set the default value of the column to 0, but it shows ((0)) as default value.
Any help would be appreciated.
If you are using this code to increment primary key value of the database table, you shouldn't be doing this way. You should be using IDENTITY column feature available in the database.
Since you have not explained why you are not using IDENTITY column, looks like this code is for some other purpose.
As per your code you are getting Maximum value of some column from the database and incrementing it by one in the code.
When the table in the database is empty you not get anything is the reader. So While loop will not be executed at all. So even if you are checking for NullOrEmpty inside the while loop, it will never get executed.
Also you don't need to use SqlDataReader here. Since you are returning only one single value from the query you can use ExecuteScalar method of SqlCommand and get that value. It will be simpler.
var codeFromDb = sqlCmd.ExecuteScalar();
var cat_next_code = 0;
if(!(codeFromDb is DBNull))
{
cat_next_code = Convert.ToInt32(codeFromDb);
}
Ctgry_CtgryCodeCb.Text = (cat_next_code + 1).ToString();
My strong recommendation is to use IDENTITY column instead of doing all this code.
This will help you resolve your current issue.
SqlDataReader is overkill in this case and I don't like to answer for the wrong approach but since you insist consider following.
SqlDataReader dr = sqlCmd.ExecuteReader();
int cat_next_code = 0;
if(dr.Read()) // while is not needed here. There will be only one row in the reader as per the query.
{
i = 1;
if(!dr.IsDBNull(0))
{
cat_next_code = int.Parse(dr[0].ToString());
}
}
Ctgry_CtgryCodeCb.Text = (cat_next_code + 1).ToString();
I want to pass a column2 to a function and update column3 with output of function. I have made func function to calculae the output. When i run the program
it only takes last value as input and outputs all columns with same value.What am i doing wrong?
sqlite1 = new SQLiteConnection("DataSource = D:/datab.db;version=3");
sqlite1.Open();
string query1 = "select * from ramrotable";
SQLiteCommand cmd = new SQLiteCommand(query1, sqlite1);
SQLiteDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("Age::" + reader["age"]);
//int data = Convert.ToInt16(reader["age"]);
string tempquery = string.Format("UPDATE ramrotable SET num =
func({0})",reader["age"]);
cmd = new SQLiteCommand(tempquery, sqlite1);
cmd.ExecuteNonQuery();
}
string query4 = "select * from ramrotable";
cmd = new SQLiteCommand(query4, sqlite1);
reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("Name: " + reader["name"] + " Age: " +
reader["age"] + " Num: " + reader["num"]);
}
You need to use a WHERE clause to tell SQLite which record to update exactly. Otherwise all records will be affected. Please make sure that in the WHERE clause you use a column (or a combination of columns) the identify the record uniquely!
Ideally, every record will have an ID column that contains a unique value and is the Primary Key.
I understand from the comments to the question that you actually want to update the value of the num column depending on a value from the age column of the same record, for all the records in the table.
To do this, you neither need to fetch all the records nor do you need to loop. All you need to do is invoke the following statement:
UPDATE ramrotable SET num = func(age)
This takes the value of the age column, passes it to func and sets the result as the new value for the num column for each record in the table.
So all of what you've written above can be shortened to
sqlite1 = new SQLiteConnection("DataSource = D:/datab.db;version=3");
sqlite1.Open();
cmd = new SQLiteCommand("UPDATE ramrotable SET num = func(age)", sqlite1);
cmd.ExecuteNonQuery();
When using
string tempquery = string.Format("UPDATE ramrotable SET num =
func({0})",reader["age"]);
you are updating each row with current func(age) value.
For updating each row with exact value you should use single command outside of the while loop:
string updatequery = "UPDATE ramrotable SET num = func(age)";
cmd = new SQLiteCommand(updatequery, sqlite1);
cmd.ExecuteNonQuery();
I'm using this code to select the maxID from a database table and each time I want to add a new record, the autogenerated ID is not the last one +1.
public formularAddCompanie()
{
InitializeComponent();
try
{
string cs = "Data Source=CODRINMA\\CODRINMA;Initial Catalog=TrafficManager;Integrated Security=True";
string select = "SELECT max(IDCompanie) FROM Companii";
using (SqlConnection con = new SqlConnection(cs))
{
con.Open();
SqlCommand cmd2 = new SqlCommand(select, con);
SqlDataReader sda = cmd2.ExecuteReader();
DataTable idmax = new DataTable("idmax");
idmax.Load(sda);
if (idmax.Rows[0][0].ToString().Trim() == "") { txtID.Text = "1"; }
else { txtID.Text = (int.Parse(idmax.Rows[0][0] .ToString() + 1).ToString()); }
}
}
catch (Exception er) { MessageBox.Show(er.Message); }
}
The table from where the selection is made, looks like this:
IDCompany Name Address City RegNo
1 A Street NY 123
Each time I want to add a new record, the autogenerated ID is like this: 11, 111, 1111. It takes the last ID and add another 1 next to it. What am I missing?
Interestingly, note that
string a = "The meaning of life is " + 42;
converts 42 to a string, creating the result
a == "The meaning of life is 42"
Look at this code:
(int.Parse(idmax.Rows[0][0] .ToString() + 1).ToString()); }
You are converting idmax.Rows[0][0] to a string and adding +1 to the end of the string rather than to an integer value. Try
(int.Parse(idmax.Rows[0][0].ToString()) + 1).ToString(); }
Note that idmax.Rows[0][0] should already have an integer in it (as pointed out in the comments). If that's the case, you can simplify to
(idmax.Rows[0][0] + 1).ToString(); }
idmax.Rows[0][0].ToString() + 1 produces string, not int.
You can try
txtID.Text = (Convert.ToInt32(idmax.Rows[0][0]) + 1).ToString();
I just add this because it seems that none cares about the weakness of the code posted by the poster.
First the MAX function is not reliable if you want to find the next autoincrement value that will be assigned to an ID column. Concurrency could wreak havoc with any schema that use MAX. Just suppose that another user has already retrieved the MAX for its own INSERT operation, then depending on the relative speed of the two computers you or the other user will insert a duplicate value for the IDCompany field.
The only correct way to do this common task is to use the IDENTITY property for the column IDCompany and when you need to insert a new record you should write something like this
try
{
string insert = "INSERT INTO Companii (Name,Address,City,RegNo)
VALUES(#name,#address,#city,#regno);
SELECT SCOPE_IDENTITY()";
using (SqlConnection con = new SqlConnection(cs))
using (SqlCommand cmd = new SqlCommand(insert, con))
{
con.Open();
cmd.Parameters.Add("#name", SqlDbType.NVarChar).Value = txtBoxCity.Text;
.... and on for the other parameters ....
int companyID = Convert.ToInt32(cmd.ExecuteScalar());
... work with the just added company if required
}
}
catch (Exception er)
{ MessageBox.Show(er.Message); }
SCOPE_IDENTITY will return the last identity value inserted into an identity column in the same scope and in this context scope means the connection used by your command.
In any case, if the MAX approach is still required then the code could be simplified a lot using a modified query and SqlCommand.ExecuteScalar instead of building an SqlDataReader, filling a datatable, trying to parse the result with ifs
string getMax = #"select COALESCE(MAX(IDCompany), 0) + 1 AS maxPlusOne
from Companii"
using(SqlConnection cnn = new SqlConnection(.....))
using(SqlCommand cmd = new SqlCommand(getMax, cnn))
{
cnn.Open();
int nextCompanyID = Convert.ToInt32(cmd.ExecuteScalar());
}
The COALESCE function checks the result of the MAX function and if it is NULL returns the second parameter (here 0), then just increment by 1 to get the next MAX directly from the database. ExecuteScalar will do the call returning just the maxPlusOne alias field
try this snippet:
Convert Your String into Int. String with + operator will con-cat and with int it will add numbers.
if (idmax.Rows[0][0].ToString().Trim() == "") { txtID.Text = "1"; }
else {
txtID.Text = Convert.ToString(Convert.ToInt32(idmax.Rows[0][0] .ToString())+1); }
Try This one, my id format is USR001.The code will generate auto id based on the last id inside the database. If the last id in the database is USR001, the the code will generate USR002 and put the id to the textbox
con.Open();
string sqlQuery = "SELECT TOP 1 kode_user from USERADM order by kode_user desc";
SqlCommand cmd = new SqlCommand(sqlQuery, con);
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
string input = dr["kode_user"].ToString();
string angka = input.Substring(input.Length - Math.Min(3, input.Length));
int number = Convert.ToInt32(angka);
number += 1;
string str = number.ToString("D3");
txtKodeUser.Text = "USR" + str;
}
con.Close();
I have a datagrid and in it I have many rows. I just want to pick up 2 columns from which one row from which one column will search the database for that row with that value and the second column will update that row with the new value. Please help.
My code which is giving a syntax error
Incorrect syntax near the keyword 'VALUES'
my code
{
using (SqlConnection con = new System.Data.SqlClient.SqlConnection("Data Source=rex;Initial Catalog=PersonalDetails;Integrated Security=True"))
{
con.Open();
for (int i = 0; i <= dataGridView2.Rows.Count - 1; i++)
{
String insertData = "UPDATE Test SET AvailableQty = " + "VALUES (#Qty) Where ItemCode = " + "VALUES (#ItemCode) ";
SqlCommand cmd = new SqlCommand(insertData, con);
cmd.Parameters.AddWithValue("#ItemCode", dataGridView2.Rows[i].Cells[0].Value ?? DBNull.Value);
cmd.Parameters.AddWithValue("#Qty", dataGridView2.Rows[i].Cells[4].Value ?? DBNull.Value);
cmd.ExecuteNonQuery();
}
}
}
First of all, you should always use parameterized queries. This kind of codes are open for SQL Injection attacks.
I think you misunderstand the syntax of Update in T-SQL.
using (SqlConnection con = new System.Data.SqlClient.SqlConnection("Data Source=rex;Initial Catalog=PersonalDetails;Integrated Security=True"))
{
con.Open();
for (int i = 0; i <= dataGridView2.Rows.Count - 1; i++)
{
string insertData = "UPDATE Test SET AvailableQty = #Qty Where ItemCode = #ItemCode";
SqlCommand cmd = new SqlCommand(insertData, con);
cmd.Parameters.AddWithValue("#ItemCode", dataGridView2.Rows[i].Cells[0].Value ?? DBNull.Value);
cmd.Parameters.AddWithValue("#Qty", dataGridView2.Rows[i].Cells[4].Value ?? DBNull.Value);
cmd.ExecuteNonQuery();
}
}
Your query string is wrong, that's why it's giving to you a syntax error:
string insertData = "UPDATE Test SET AvailableQty = #Qty WHERE ItemCode = #ItemCode";
And please try to avoid using the String class: look here.
You have wrong update query change your query like
String insertData = "UPDATE Test SET AvailableQty = #Qty Where ItemCode = #ItemCode";
For more information click here
For Getting the availableQty from database use select query like
Select availableQty from tablename where `use here primary value column and it's value'
like i have id as a primary column with value 1 then i write
Select availableQty from tablename where id = 1
After getting value you can easily substract like
double substractval = availableQty - dataGridView2.Rows[i].Cells[4].Value;
Now at last use your update query like
Update tablename set availableQty = '"+substractval +"' where "pass primary column and value
You have to use this type of scenario.
Hope you understand and works for you.