Updating through SqlDataAdapter and DataSet in C# - c#

I have the fol code
string user = "new user";
DataSet myDS = new DataSet();
string sql = string.Format("Select Counter,Occupants From Rooms where Room = '{0}'",room);
SqlDataAdapter dAdapt = new SqlDataAdapter(sql, cnn);
dAdapt.Fill(myDS, "Rooms");
foreach (DataTable dt in myDS.Tables)
{
int var =(int) dt.Rows[0].ItemArray[0];
var--;
dt.Rows[0].ItemArray[0] = var;
String occups = dt.Rows[0].ItemArray[1].ToString();
occups += user;
dt.Rows[0].ItemArray[1] = occups;
}
dAdapt.Update(myDS,"Rooms");
I'm retrieving a single row with two columns-- Counter(small int type) and Occupants(text type). I get an error saying that the data types text and var char are incompatible in the equal to operator But the error is pointed to the line dAdapt.Fill(myDS, "Rooms"); which is weird. What's wrong here? And I'm pretty sure that the db connection is open as I've checked it by printing the connection status.

This won't work anyway unless you have specified an Update-Command for the DataAdaper.
I would not load the record into memory to update it. Meanwhile it could have been changed from another transaction. It's inefficient anyway. Instead i would use a single update-command:
string updateSql = #"
UPDATE ROOMS SET
Counter = Counter + 1,
Occupants = Occupants + ',' + #newUser
WHERE
Room = #Room";
using(var con = new SqlConnection(connectionString))
using (var updateCommand = new SqlCommand(updateSql, con))
{
updateCommand.Parameters.AddWithValue("#newUser", user);
updateCommand.Parameters.AddWithValue("#Room", room);
con.Open();
updateCommand.ExecuteNonQuery();
}

The problem is in your select, because you can use the syntax, that Room = 'something', because text is not compatible with =.
Use LIKE instead of equal sign (=).
Fixed query should look like:
SELECT Counter,Occupants FROM Rooms WHERE Room LIKE '{0}'
But I recommand to use SqlParameters instead of string.Format, because it is not secure.

Related

sql query to show data from price between two columns C#

EDIT: I am not able to format my code below, if any one can fix it.
I am new to sql queries and still learning.
Table Name: CommissionSetupTable.
I want to display #Paisa if gross_amount is between the range of #FromRate and #ToRate
Below is my code:
string paisa;
private void load_commission_setup()
{
SqlCeConnection conn = null;
SqlCeCommand cmd = null;
SqlCeDataReader rdr = null;
try
{
conn =
new SqlCeConnection(
#"Data Source=|DataDirectory|\Database.sdf;Persist Security Info=False");
conn.Open();
int rowindex = purchaseBillTableDataGridView.Rows.Count - 1;
gross_amount = double.Parse(purchaseBillTableDataGridView[10, rowindex].Value.ToString());
// Gross Amount is between the ranges of FromRate and ToRate.
cmd = new SqlCeCommand("SELECT Paisa FROM CommissionSetupTable WHERE='" + gross_amount.ToString() + "' BETWEEN #FromRate AND #ToRate;", conn);
rdr = cmd.ExecuteReader();
if (rdr == null)
{
}
else
{
while (rdr.Read())
{
paisa = rdr["Paisa"].ToString();
}
rdr.Close();
cmd.Dispose();
}
}
finally
{
conn.Close();
int rowindex = purchaseBillTableDataGridView.Rows.Count - 1;
purchaseBillTableDataGridView[11, rowindex].Value = paisa;
}
}
The correct syntax to use here is the following
cmd = new SqlCeCommand(#"SELECT Paisa FROM CommissionSetupTable
WHERE #gross BETWEEN FromRate AND ToRate;", conn);
Notice that the two field names should not be prefixed with #, otherwise they will be considered parameters placeholders.
And now, before executing the command, add the parameter for the #gross placeholder
cmd.Parameters.Add("#gross", SqlDbType.Decimal).Value = gross_amount;
I don't know what is the exact datatype of the columns FromRate and EndRate, but
note that you should use the correct datatype for your parameter. Do not pass a string and expect the database engine do the conversion for you. (or worse concatenate your value to the rest of the sql using ToString()). This is always wrong also if sometime the database engine could understand your values.
EDIT
Also, following your comments below, it appears that this line is wrong
int rowindex = purchaseBillTableDataGridView.Rows.Count - 1;
If your DataGridView has the property AllowUserToAddRow set to True then you want to use
int rowindex = purchaseBillTableDataGridView.Rows.Count - 2;
because the first line points to the empty row added to the DataGridView for inserting a new record.

The conversion of the varchar value '5566778891' overflowed an int column

I am using SQL Server database and there's a column named Cell(VARCHAR) data type. While reading using reader.Read() I get the Conversion error. Can anyone kindly explain the reason for the error?
This is my code:
string myConnection = dbController.connectionString;
string query1 = "SELECT ID, Name from Manager Where Cell = " + managerNo.Text;
using (var conn = new SqlConnection(myConnection))
using (var cmd = new SqlCommand(query1, conn))
{
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
managerID = reader.GetString(0);
mgrID.Text = managerID;
managerNames.Text = reader.GetString(1);
}
conn.Close();
}
I am reading the value from a textbox (managerNo). I have tested the query on SQL Server Management Studio as well:
select Name, DOB
from Contact
where Cell = 1233453411
When I use Cell = 1233453411 without the value as string I get the conversion error, however using Cell = '1233453411' as a string the result is fetched.
Whats the reason for this and how to solve this issue.
Thanks.
This is a comparison between two different types, a string and an integer:
where Cell = 1233453411
SQL Server has to decide which type to use. It decides on the more restrictive type, which is the number. So, the string gets converted to a number.
Say, you have a cell phone in New York with a number like: 917-555-5555. Well, that becomes a number like 9,175,555,555 and this exceeds the value of the maximum integer. Hence, you would get a conversion overflow.
The moral: Always use similar types when making comparisons.
EDIT:
What should you do? Don't store telephone numbers as numbers; they should be stored as strings (for instance, leading zeroes can be important).
If could do a quick-and-dirty and put single quotes around the value of the parameter. But, what you should really do is change your SQL code to use a parameter with a string type. It is bad programming to just stuff values (particularly user input) into a query string.
Your code is working fine in SQL Server 2008 R2. (Below is tested code)
private void button1_Click(object sender, EventArgs e)
{
string str = "Server=.\\SQL2008R2;Database=Practice;User ID=sa;Password=123;Trusted_Connection=True;Connection Timeout=0";
string query1 = "SELECT * from tblTest Where Cell = " + textBox1.Text;
using (var conn = new SqlConnection(str))
using (var cmd = new SqlCommand(query1, conn))
{
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
string aa = reader.GetString(0);
}
conn.Close();
}
Otherwise using can change you query like in below format.
string query1 = "SELECT * from tblTest Where Cell = '" + textBox1.Text + "' ";
Thanks

Auto generate and AutoIncrement ID in C# when trying to add new record to database

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();

Adapter.Fill takes long

I've created a RadGrid Programmatically and binding it using NeedDataSource -> GetDataTable.
Within the GetDataTable, I'm calling my connstring and fill the grid with an adapter (see code below). Problem is that, in my SQL Server, the query takes 0 sec to run, but in the ASP.NET debug mode, it's taking about 3~5s, in my case of having a lot of RadGrids on the page, this is causing my page to load slowly.
Is this processing speed of adapter.Fill a general issue or have I done something wrong with the setting? (ie, orders of conn.open/close or any others)?
public DataTable GetDataTable(int Year, int month, string datatype)
{
String ConnString = ConfigurationManager.ConnectionStrings["IHG_MSTConnectionString"].ConnectionString;
SqlConnection conn = new SqlConnection(ConnString);
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand("[Yield_Planner_With_Strategy]", conn);
adapter.SelectCommand.CommandType = System.Data.CommandType.StoredProcedure;
adapter.SelectCommand.Parameters.AddWithValue("#Holidex_Code", RadComboBox_Hotels.SelectedValue);
adapter.SelectCommand.Parameters.AddWithValue("#Event_Year", Year);
adapter.SelectCommand.Parameters.AddWithValue("#Event_Month", month);
adapter.SelectCommand.Parameters.AddWithValue("#DataType", datatype);
adapter.SelectCommand.Parameters.AddWithValue("#MktSeg", Fruitful.Get_Checked_Values_As_CSV(RadComboBox_MktSeg));
string exportdate = DateTime.Now.ToString("yyyy/MM/dd");
if (RadComboBox_ExportTimeStamp.Text != "" && RadComboBox_ExportTimeStamp.Text != "Create New Strategy")
{ exportdate = Convert.ToDateTime(RadComboBox_ExportTimeStamp.Text).ToString("yyyy/MM/dd"); }
adapter.SelectCommand.Parameters.AddWithValue("#ExportTimeStamp", exportdate);
DataTable myDataTable = new DataTable();
conn.Open();
try
{
adapter.Fill(myDataTable);
}
finally
{
conn.Close();
}
return myDataTable;
}
Why do you use a string for the ExportTimeStamp parameter? Use
DateTime if it's a date or datetime column.
I'd also replace all of your calls to AddWithValue with Add. When you call AddWithValue it has to guess what the type of your parameter is. If it guesses wrong the optimizer cannot select the correct index and falls back to a table scan, and that speaks to the core of database performance.
AddWithVaue may result in multiple query plans. Since .NET doesn't know what the size of the database column is, it will use the size of the variable. so if you have a parameterized query and pass two strings in, one of length 10, the other of length 20, you will get two plans: #text nvarchar(10) and #text nvarchar(20). It will also assume that your field is nvarchar when it may be varchar and you will get an implicit conversion.
So always either pass the correct type to AddWithValue or (better) use SqlParameterCollection.Add with the correct type and size. It'll also validate the parameter before it gets sent to the database.
Related:
SqlCommand Parameters Add vs. AddWithValue
Bad habits to kick : mis-handling date
The Seven Sins against TSQL Performance
Also, use the using-statement to ensure that the connection gets closed as soon as you're finished with it - even in case of an error.
Here is an example:
public DataTable GetDataTable(int Year, int month, string datatype)
{
DataTable myDataTable = new DataTable();
String ConnString = ConfigurationManager.ConnectionStrings["IHG_MSTConnectionString"].ConnectionString;
using(SqlConnection conn = new SqlConnection(ConnString))
using (SqlDataAdapter adapter = new SqlDataAdapter())
{
var cmd = new SqlCommand("[Yield_Planner_With_Strategy]", conn);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add("#Holidex_Code", SqlDbType.Int).Value = int.Parse(RadComboBox_Hotels.SelectedValue);
cmd.Parameters.Add("#Event_Year", SqlDbType.Int).Value = Year;
cmd.Parameters.Add("#Event_Month", SqlDbType.Int).Value = month;
cmd.Parameters.Add("#DataType", SqlDbType.VarChar).Value = datatype;
cmd.Parameters.Add("#MktSeg", SqlDbType.NVarChar).Value = Fruitful.Get_Checked_Values_As_CSV(RadComboBox_MktSeg);
DateTime exportdate = DateTime.Now;
if (RadComboBox_ExportTimeStamp.Text != "" && RadComboBox_ExportTimeStamp.Text != "Create New Strategy")
{
exportdate = DateTime.Parse(RadComboBox_ExportTimeStamp.Text);
}
cmd.Parameters.Add("#ExportTimeStamp", SqlDbType.DateTime).Value = exportdate;
adapter.SelectCommand = cmd;
// you don't need to open it with Fill
adapter.Fill(myDataTable);
}
return myDataTable;
}

c# - Optimize SQLite Select statement

I am using System.Data.SQLite for my database, and my select statements are very slow. It takes around 3-5 minutes to query around 5000 rows of data. Here is the code I am using:
string connectionString;
connectionString = string.Format(#"Data Source={0}", documentsFolder + ";Version=3;New=False;Compress=True;");
//Open a new SQLite Connection
SQLiteConnection conn = new SQLiteConnection(connectionString);
conn.Open();
SQLiteCommand cmd = new SQLiteCommand();
cmd.Connection = conn;
cmd.CommandText = "Select * From urls";
//Assign the data from urls to dr
SQLiteDataReader dr = cmd.ExecuteReader();
SQLiteCommand com = new SQLiteCommand();
com.CommandText = "Select * From visits";
SQLiteDataReader visit = com.ExecuteReader();
List<int> dbID2 = new List<int>();
while (visit.Read())
{
dbID2.Add(int.Parse(visit[1].ToString()));
}
//Read from dr
while (dr.Read())
{
string url = dr[1].ToString();
string title = dr[2].ToString();
long visitlong = Int64.Parse(dr[5].ToString());
string browser = "Chrome";
int dbID = int.Parse(dr[0].ToString());
bool exists = dbID2.Any(item => item == dbID);
int frequency = int.Parse(dr["visit_count"].ToString());
bool containsBoth = url.Contains("file:///");
if (exists)
{
if (containsBoth == false)
{
var form = Form.ActiveForm as TestURLGUI2.Form1;
URLs.Add(new URL(url, title, browser, visited, frequency));
Console.WriteLine(String.Format("{0} {1}", title, browser));
}
}
}
//Close the connection
conn.Close();
And here is another example that takes long:
IEnumerable<URL> ExtractUserHistory(string folder, bool display)
{
// Get User history info
DataTable historyDT = ExtractFromTable("moz_places", folder);
// Get visit Time/Data info
DataTable visitsDT = ExtractFromTable("moz_historyvisits",
folder);
// Loop each history entry
foreach (DataRow row in historyDT.Rows)
{
// Select entry Date from visits
var entryDate = (from dates in visitsDT.AsEnumerable()
where dates["place_id"].ToString() == row["id"].ToString()
select dates).LastOrDefault();
// If history entry has date
if (entryDate != null)
{
// Obtain URL and Title strings
string url = row["Url"].ToString();
string title = row["title"].ToString();
int frequency = int.Parse(row["visit_count"].ToString());
string visit_type;
//Add a URL to list URLs
URLs.Add(new URL(url, title, browser, visited, frequency));
// Add entry to list
// URLs.Add(u);
if (title != "")
{
Console.WriteLine(String.Format("{0} {1}", title, browser));
}
}
}
return URLs;
}
DataTable ExtractFromTable(string table, string folder)
{
SQLiteConnection sql_con;
SQLiteCommand sql_cmd;
SQLiteDataAdapter DB;
DataTable DT = new DataTable();
// FireFox database file
string dbPath = folder + "\\places.sqlite";
// If file exists
if (File.Exists(dbPath))
{
// Data connection
sql_con = new SQLiteConnection("Data Source=" + dbPath +
";Version=3;New=False;Compress=True;");
// Open the Connection
sql_con.Open();
sql_cmd = sql_con.CreateCommand();
// Select Query
string CommandText = "select * from " + table;
// Populate Data Table
DB = new SQLiteDataAdapter(CommandText, sql_con);
DB.Fill(DT);
// Clean up
sql_con.Close();
}
return DT;
}
Now, how can I optimize these so that they are faster?
In addition to moving more of the data aggregation to SQL as joins, you might also consider getting your SQLiteDataReader to provide the data types instead of always parsing the values.
For example, you have the line:
long visitlong = Int64.Parse(dr[5].ToString());
dr[5] is a Sqlite value which you are first converting to a string, then parsing it to a long. These parse operations take time. Why not instead do:
long visitlong = dr.GetInt64(5);
Or:
long visitlong = dr.GetInt64(dr.GetOrdinal("columnName"));
Check out the various methods that SqliteDataReader offers and utilize them whenever possible instead of parsing values.
Edit:
Note that this requires the data be stored as the correct type. If everything in the database is stored as a string, some parsing will be unavoidable.
Make sure that you've recently run the SQL command "ANALYZE {db|table|index};".
I recently ran into a situation where queries were running fast (<1 sec) in my ER software (Navicat), ie: not debugging, but they were very slow (>1 min) debugging in Visual Studio. It turned out that because I did my database design in Navicat (SQLite v3.7), the statistics were not the same as those used by System.Data.SQLite in Visual Studio (v3.8). Running "ANALYZE;" on the entire database file from Visual Studio updated the [sqlite_statX] tables used by v3.8. Both places were the same speed after that.

Categories

Resources