C#: OleDbCommand Update query not working? - c#

I have a database with multiple rows and columns with default value of 0. The user have to select a column by typing in the column name in a textBox and the system will automatically increment the value in the column by 1.
using (OleDbCommand cmd2 = connection.CreateCommand())
{
int i = 1;
cmd2.CommandText = "Update NormalRoom1 SET #time = #time + #b where [Appointment_Date]= #date";
// add parameters
cmd2.Parameters.AddRange(new OleDbParameter[]
{
// a is a string variable that holds a value the user chooses
new OleDbParameter("#time", a),
new OleDbParameter("#b", i),
new OleDbParameter ("#date", dateTimePicker2.Value.ToString("dd/MM/yyyy"))
});
// execute
cmd2.ExecuteNonQuery();
}

Only values can be variables. Your #time would be a column name and that cannot be a variable. As much as I hate to say this: you will need to insert that part by text-format.
Please be extra careful when doing so, it's an attack vector for sql injection. Best scenario is you let the user pick from a combobox and then check his selection against an internal list again.

Related

How to get all the values in a row of a DB relation and assign each of them to a variable in ASP.NET C#

I'm trying to find a way to have access to all the values in a row.
The following code returns one cell. If I change select id to select *, I have access to the row but how can I break it apart?
string find_user = "select id from users where userName = '" + un + "'";
using (SqlConnection con = new SqlConnection(cs))
{
using (SqlCommand cmd = new SqlCommand(find_user, con))
{
con.Open();
user_id = cmd.ExecuteScalar().ToString();
/* use to pass the info to all the pages */
Session.Add("u_id", user_id);
}
}
You cannot access additional columns using .ExecuteScalar(), per the docs:
Executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored.
Although it is not a route that I would recommend, you can iterate through the fields by using an index on a data reader:
SqlDataReader dataReader = cmd.ExecuteReader();
// for the query's result set, this while loop will go through all the records
while (dataReader.Read())
{
// for the current record, this for loop will go through all the fields
for (int i = 0; i < dataReader.FieldCount; i++)
{
var value = dataReader[i]; // do what you need with the data here
}
}
A better approach would be to specify the field names in the SQL query instead of using SELECT *, then get the values from the data reader by the specific field names (not relying on the order of the fields in the DB).
Also, you have a SQL injection vulnerability. You should look up what this means and how to parameterize a query.

How to insert/update information in SQL Server

I am trying to insert new information into my already created table where id = 2019;
I get the error incorrect syntax near WHERE:
private void button6_Click(object sender, EventArgs e)
{
xcon.Open();
SqlDataAdapter xadapter = new SqlDataAdapter();
xadapter.InsertCommand = new SqlCommand("INSERT into dbo.SysX VALUES (#fpp, #sdd, #sff) WHERE id = 2019", xcon);
xadapter.InsertCommand.Parameters.Add("#fpp", SqlDbType.Int).Value = Convert.ToInt32(textBox1.Text);
xadapter.InsertCommand.Parameters.Add("#sdd", SqlDbType.Int).Value = Convert.ToInt32(textBox2.Text);
xadapter.InsertCommand.Parameters.Add("#sff", SqlDbType.Int).Value = Convert.ToInt32(textBox3.Text);
xadapter.InsertCommand.ExecuteNonQuery();
xcon.Close();
}
How can I insert new information on click of button where ID = 2019?
You need to change the below line
xadapter.InsertCommand = new SqlCommand("INSERT into dbo.SysX VALUES (#fpp, #sdd, #sff) WHERE id = 2019", xcon);
to the as below line if you want to insert value/row into the table.
xadapter.InsertCommand = new SqlCommand("INSERT into dbo.SysX VALUES (#fpp, #sdd, #sff)", xcon);
If you want to update existing record then you need to replace your SQL Statement as
"Update dbo.SysX Set <Col1> = #fpp, <Col2> = #sdd, ... where id = 2019"
You can check this Answer and this link.
INSERT and UPDATE are two really separate SQL commands. As their name suggests, with INSERT you add new record to a table, with UPDATE you edit existing record, so either you provide a pointer to an existing record to edit it
UPDATE Table SET Column = data WHERE Field = ‘x’
or you just provide a number of values to be inserted
INSERT INTO Table (Columns) VALUES (Data)
On a side note, such insertions or updates are best done with stored procedures, in order to avoid sql injection attacks.

How to read 1 record from a sql server database into a c# textbox?

I want to do this (on Form3):
sqlcon.Open();
string selectQuery = "SELECT * FROM InvoiceTable where id = #id";
SqlCommand sqlcmd = new SqlCommand(selectQuery, sqlcon);
sqldr = sqlcmd.ExecuteReader();
while(sqldr.Read())
{
textbox1 = Max value of TotalCostColumn.value
or
textbox1 = Latest value of TotalCostColumn.value
or
textbox1 = 2nd row of TotalCostColumn.value
}
Im not having any datagridview on this form. I do have a datagridview on Form1 which is the actual invoice form. Form3 is the confrimation form which lets the user confirm how much customer should pay eventually. I want the TotalCostColumn's value from my database to be transfered in the related textbox in Form3.
textbox1 = Max value of TotalCostColumn.value
If that's your requirement then why not build the query as per like
SELECT max(TotalCostColumn) FROM InvoiceTable where id = #id
And then instead of using ExecuteReader() you should call ExecuteScalar() which would return a single value
This is how you'd get the Max value with ExecuteScalar:
string selectQuery = "SELECT MAX(TotalCostColumn) FROM InvoiceTable where id = #id";
var sqlcmd = new SqlCommand(selectQuery, sqlcon);
var result = sqlcmd.ExecuteScalar();
return int.Parse(result.ToString());
MAX will ensure you only get one row from the table.
To get the latest value, you'd have to sort the table (I assume there's a transaction date) and add TOP 1 to get only the first row. (Although ExecuteScalar will ignore everything except the first field of the top row but there's no point returning data you don't need)
There are two ways to get the second row. One is to use a datareader and skip over the first row. The other is with SQL:
SELECT TOP 1 FROM
(
SELECT TOP 2 TotalCost FROM InvoiceTable where id = #id ORDER BY TotalCost DESC
) ORDER BY TotalCost ASC
Here the inner query gets two rows of data sorted with the largest item first, and the outer query picks the lower value of the two.
You need to write a stored procedure which accepts the value of the id
stored procedure is defined as follows
create proc selectmax(#id int)
as begin
select max(TotalCostColumn) FROM InvoiceTable where id = #id
end
and call it as below using Disconnected Model so sqlcon.open() is not Required
SqlCommand sqlcmd = new SqlCommand(selectmax, sqlcon);
sqlcmd.CommandType=CommandType.StoredProcedure
SqlDataAdapter adapter= new SqlDataAdapter(sqlcmd);
DataSet value=new DataSet();
adapter.Fill(value);
This is the implementation using Ado.net Disconnected Model

Getting the PK of a record before being saved on the database sqlserver and C#

Good day guys,
I am creating a system for saving details of a user, i have attributes (UserID(pk-Auto),name,surname,disability(FK)..
I have 3 tables, being
user ( UserID(pk), Name, surname, disability(fk) )
disability ( DisabilityID(pk), Disability(YES/NO) )
disabilitype ( DisabilityTypeID(PK), disabilityID(fk), UserID(fk), disabilityName )
The disability have an option of yes/now(with the id for yes being 1 and 2 for no), if the user clicks yes the system must be able to save data on disabilityType and retrieve the PK of user of which it is unknown because the user details will saved afer the if statement of the disability attribute
if you mean you want the id of the next entered row before save it you can get it by making a trick first get the last entered id.for example if you have table called user and the primary key is Id you can select last entered id by this query SELECT IDENT_CURRENT('user') and then the next id is the output value +1
You should be able to use ##Identity to get at the id that was generated by the statement. So when you insert into the User table add an out parameter that returns the ##Identity, then use that value to save int the disabilitype table accordingly.
using (SqlCommand cmd = new SqlCommand("Insert Into User ... //Brevity
RETURN ##IDENTITY
", cn)) {
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter returnValue = new SqlParameter();
returnValue.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(returnValue);
cmd.ExecuteNonQuery();
}

c# OleDB Doesn't update database [duplicate]

I have been trying to use OleDbDataAdapter to update a DataTable but got confused about the commands.
Since I sometimes get info from diffrent tables I can't use a CommandBuilder.
So I have tried to create the commands on my on but found it hard with the parameters.
DataTable.GetChanges returns rows that needs to use an INSERT or an UPDATE command - I guess I can't distinct between them.
I need you to complete the following:
DataTable dt = new DataTable();
OleDbDataAdapter da = new OleDbDataAdapter();
// Here I create the SELECT command and pass the connection.
da.Fill(dt);
// Here I make changes (INSERT/UPDATE) to the DataTable (by a DataGridView).
da.UpdateCommand = new OleDbCommand("UPDATE TABLE_NAME SET (COL1, COL2, ...) VALUES (#newVal1, #newVal2, ...) WHERE id=#id"); // How can I use the values of the current row (that the da is updating) as the parameters (#newVal1, #newVal2, id....)?
Thank you very much!
The data adapter can work in conjunction with the datatable. As such, I've actually wrapped mine together into a class and works quite well. Aside from the complexities of my stuff, here's a snippet that might help you along. When adding a parameter, you can identify the column source that the data is coming from FROM the DataTable. This way, when a record is internally identified as "Added" or "Updated" (or "Deleted"), when you build your SQL Insert/Update/Delete commands, it will pull the data from the columns from the respective rows.
For example. Say I have a DataTable, primary Key is "MyID" and has columns "ColX, ColY, ColZ". I create my DataAdapter and build out my select, update, delete commands something like... (? is a place-holder for the parameters)
DataAdapter myAdapter = new DataAdapter()
myAdapter.SelectCommand = new OleDbCommand();
myAdapter.InsertCommand = new OleDbCommand();
myAdapter.UpdateCommand = new OleDbCommand();
myAdapter.DeleteCommand = new OleDbCommand();
myAdapter.SelectCommand.CommandText = "select * from MyTable where MyID = ?";
myAdapter.InsertCommand.CommandText = "insert into MyTable ( ColX, ColY, ColZ ) values ( ?, ?, ? )";
myAdapter.UpdateCommand.CommandText = "update MyTable set ColX = ?, ColY = ?, ColZ = ? where MyID = ?";
myAdapter.DeleteCommand.CommandText = "delete from MyTable where MyID = ?";
Now, each has to have their respective "Parameters". The parameters have to be addded in the same sequence as their corresponding "?" place-holders.
// Although I'm putting in bogus values for preparing the parameters, its just for
// data type purposes. It does get changed through the data adapter when it applies the changes
OleDbParameter oParm = new OleDbParameter( "myID", -1 );
oParm.DbType = DbType.Int32;
oParm.SourceColumn = "myID"; // <- this is where it looks back to source table's column
oParm.ParameterName = "myID"; // just for consistency / readability reference
myAdapter.SelectCommand.Parameters.Add( oParm );
do similar for rest of parameters based on their types... char, int, double, whatever
Again, I have like a wrapper class that handles managment on a per-table basis... in brief
public myClassWrapper
{
protected DataTable myTable;
protected DataAdapter myAdapter;
... more ...
protected void SaveChanges()
{
}
}
Its more complex than just this, but during the "SaveChanges", The datatable and dataAdapter are in synch for their own purposes. Now, flushing the data. I check for the status of the table and then you can pass the entire table to the dataAdapter for update and it will cycle through all changed records and push respective changes. You'll have to trap for whatever possible data errors though.
myAdapter.Update( this.MyTable );
As it finds each "changed" record, it pulls the values from the Column Source as identified by the parameter that is found in the table being passed to the adapter for processing.
Hopefully this has given you a huge jump on what you are running into.
---- COMMENT PER FEEDBACK ----
I would put your update within a try/catch, and step into the program to see what the exception is. The message adn/or inner exception of the error might give more info. However, try to simplify your UPDATE to only include a FEW fields with the WHERE "Key" element.
Additionally, and I oopsed, missed this from first part answer. You might have to identify the datatable's "PrimaryKey" column. To do so, its a property of the DataTable that expects and array of columns that represent the primary key for the table. What I did was...
// set the primary key column of the table
DataColumn[] oCols = { myDataTbl.Columns["myID"] };
myDataTbl.PrimaryKey = oCols;
I would comment out your full update string and all its parameters for your UPDATE. Then, build it with just as simple as my sample of only setting 2-3 columns and the where clause
myAdapter.UpdateCommand.CommandText = "update MyTable set ColX = ?, ColY = ? where MyID=?";
Add Parameter object for "X"
Add Parameter object for "Y"
Add Parameter object for "MyID"
Pick fields like int or char so they have the least probability of problems for data type conversions, then, once that works, try adding all your "int" and "character" columns... then add any others. Also, which database are you going against. SOME databases don't use "?" as placeholder in the command but use "named" parameters, some using
"actualColumn = #namedCol"
or even
"actualColumn = :namedCol"
Hope this gets you over the hump...
You could use the String.Format Method to replace the #newVal1, #newVal2, ... in your code, like this da.UpdateCommand = new OleDbCommand(String.Format("UPDATE TABLE_NAME SET (COL1, COL2, ...) VALUES ({0}, {1}, ...) WHERE id=#id",OBJECT_ARRAY_CONTAINING_VALUES_FROM_THEDG));
[Eidt per comment]
To handle the row[0], row[1] you need a loop like:
for(i=0; i<rows.Count; i++)
{
da.UpdateCommand = new OleDbCommand(String.Format("UPDATE...",row[i]);
da.Update(dt);
}

Categories