delete specific entries in table - c#

In my table I have many rows with data.
One row has seven columns with values.
Is it possible to delete from one row values of two columns and rest five leave without changes?
Can I to it with SQL delete?
cmd.CommandText = #"DELETE ImageData,"
+ " ContentType, "
+ " FROM Users "
+ " WHERE UserName = #UserName";
cmd.Parameters.Add(new SqlParameter("#UserName", username));
cmd.Parameters.Add(new SqlParameter("#ImageData", ImageData));
cmd.Parameters.Add(new SqlParameter("#ContentType", ContentType));
In my code I can't delete like this, is it wrong?
Does anyone know how to delete them?

I assume it's not DELETE you need but UPDATE.
DELETE always removes an entire row.
UPDATE allows you to change individual columns in a row.
codefragment
#"UPDATE Users "
+ "SET ContentType = NULL, "
+ " ImageData = NULL "
+ "WHERE Username = #UserName";

You need to use an UPDATE statement for this. DELETE is only for deleting whole row(s) at a time.
You can't actually "delete" them as though it was cells in a spreadsheet though. Assuming the columns are nullable you can set them to NULL as below.
cmd.CommandText = #"UPDATE ImageData
SET ContentType = NULL, Users = NULL
WHERE UserName = #UserName";
cmd.Parameters.Add(new SqlParameter("#UserName", username));

you could update the row:
UPDATE Users
SET ImageData = NULL, ContentType = NULL
WHERE UserName = #UserName

Related

Error in Updating a Record

Hello Everyone I'm new in here. I am currently making an asp.net project monitoring module. At this moment I am in the process of editing the project form and adding resources to the selected task in a project.
I'm having a problem in saving the record. Everytime I save the record it says
"Column name or number of supplied values does not match table
definition."
In my ProjectTasks Table I have RefNo(PK), TaskID(FK), Name and Description
Name - refers to the Task Name
Description - refers to the Task Description
What I want to happen is that my Resource Tables TaskID(FK) will be updated when I clicked the save button. As of now when I add a Resource from a task the TaskID = 0.
protected void btnSave_Click(object sender, EventArgs e)
{
con.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = "INSERT INTO ProjectTasks VALUES (#Name, #Description); " +
"SELECT TOP 1 TaskID FROM ProjectTasks ORDER BY TaskID DESC;";
cmd.Parameters.AddWithValue("#Name", txtName.Text);
cmd.Parameters.AddWithValue("#Description", txtDescription.Text);
int taskID = (int)cmd.ExecuteScalar();
con.Close();
con.Open();
cmd.CommandText = #"UPDATE Resource_Materials SET TaskID=#TaskID WHERE TaskID=0; " +
"UPDATE Resource_Equipments SET TaskID=#TaskID WHERE TaskID=0; " +
"UPDATE Resource_Vehicles SET TaskID=#TaskID WHERE TaskID=0; " +
"UPDATE Resource_Contractors SET TaskID=#TaskID WHERE TaskID=0;";
cmd.Parameters.AddWithValue("#TaskID", taskID);
cmd.ExecuteNonQuery();
con.Close();
Helper.AddLog("1", "Add", "Assigned Resources to Task");
Response.Redirect("~/Projects/Default.aspx");
}
Sorry about my grammar I'm just a student.
You said
ProjectTasks Table I have RefNo(PK), TaskID(FK), Name and Description
In such case, your INSERT query should look like below instead, specify the exact column name you are trying to insert values and as well you are missing TaskID(FK) column in your current insert query
INSERT INTO ProjectTasks(TaskID, Name, Description)
VALUES (#TaskID, #Name, #Description);
In an insert statement, we need to supply the column names when we don't want to specify values for all columns. If we don't do this we need so supply values for all columns.
In your case, you just want to provide values for Name and Description so you can do something like:
INSERT INTO ProjectTasks(Name, Description) VALUES (#Name, #Description);
Your logic is misleading..
Your ProjectTasks has 4 columns but you try to insert 2 column value in your insert statement without declaring them after your table name as ProjectTasks (Name, Description).
But this still generate a problem because your first column is PK and second one is FK. Since FK can be null but PK can't be null as far as I know, that's why you need to re-think your inserting logic.
But even if you fix it, your code still has a problem. Since you set a new string to your CommandText property, your #Name and #Description parameters were still belongs on your cmd object. That's why on ExecuteNonQuery line, your cmd will have 3 parameters as #Name, #Description and #TaskID but your command has only 1 parameter. As you can see, you will get an error such as; the parameter you supplied and command doesn't match or something. In such a case, you need to Clear() your parameters before you set new CommandText or generate a new SqlCommand object as cmd = new SqlCommand()
Also use using statement to dispose your connection and commands automatically instead of calling .Close() or .Dispose() methods manually.
And don't use AddWithValue method anymore. It may generate unexpected results sometimes. Use Add method overloads to specify your parameter type and it's size.
Solved it by removing ExecuteScalar and by replacing INSERT statement into UPDATE statement instead.
con.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = "UPDATE ProjectTasks SET Name=#Name, Description=#Description " +
"WHERE TaskID=#TaskID; " +
"SELECT TOP 1 TaskID FROM ProjectTasks ORDER BY TaskID DESC;";
cmd.Parameters.AddWithValue("#Name", txtName.Text);
cmd.Parameters.AddWithValue("#Description", txtDescription.Text);
cmd.Parameters.AddWithValue("#TaskID", Request.QueryString["ID"].ToString());
cmd.CommandText = #"UPDATE Resource_Materials SET TaskID=#TaskID WHERE TaskID=0; " +
"UPDATE Resource_Equipments SET TaskID=#TaskID WHERE TaskID=0; " +
"UPDATE Resource_Vehicles SET TaskID=#TaskID WHERE TaskID=0; " +
"UPDATE Resource_Contractors SET TaskID=#TaskID WHERE TaskID=0;";
cmd.ExecuteNonQuery();
con.Close();
Helper.AddLog("1", "Add", "Assigned Resources to Task");
Response.Redirect("~/Projects/Default.aspx");

Reduce the number of SqlCommands required to send information to three tables

I have the following code:
command = new SqlCommand("SELECT UserId from Users WHERE Username = N'" + userName + " AND " + userPassword + "= N'" + userPassword + "AND AccountStatus = 0");
command.CommandType = System.Data.CommandType.Text;
command.Connection = conn;
int uid = (int)command.ExecuteScalar();
if(uid > 0)
{
command = new SqlCommand("UPDATE IsOnline =" + true + " WHERE UserId = 'N" + uid);
command.ExecuteNonQuery();
command = new SqlCommand("INSERT INTO LogonHistory OUTPUT LogonHistoryId VALUES(NULL," + uid + "," + DateTime.Now + ")");
int id = (int) command.ExecuteNonQuery();
command = new SqlCommand("INSERT INTO UsersLogOnHistory VALUES(NULL," + uid + "," + id + ")");
command.ExecuteNonQuery();
IsAuthorised = true;
SendMessage(ID, ServerCommands.Success, IsAuthorised.ToString());
}
else
{
// User does not exist
SendMessage(ID, ServerCommands.Failed, IsAuthorised.ToString());
}
The first SQLCommand executed checks to see if the Username and password are correct and if their account is not suspended. It then (should) return the Row ID.
If the RowID > 0 then we have a valid logon.
Next SQLCommand updates the IsOnline status within the same table
The next SQLCommand Inserts into the LogonHistory the Users ID, and the DateTime. Now setting id with the Row Id
finally the SQLCommand is executed to insert the RowId we got from the last command and the User's Id into UserLogOnHistory. (which allows us to do a quick look up) - theoretically for updating the LogonHistory for when this user logs off.
I now realise that this is a mess!
So to the Questions:
How do I get the RowId of the table affected by the last command.
How can I optimise the queries to reduce the number of SQLCommands executed - or does this seem reasonable.
You can issue multiple TSQL commands in one batch by simply... including multiple TSQL commands. To be thorough, you should delimit them with ;, but in most (not all) cases, that is optional and it will work without.
To get the most recently inserted identity value; SCOPE_IDENTITY(). This only works for INSERT, and only with there is an IDENTITY column. In all other cases: OUTPUT.
Note; you should parameterize, but consider:
UPDATE IsOnline = 1 WHERE UserId = #uid;
DECLARE #lhid int
INSERT INTO LogonHistory (explict columns here)
VALUES(NULL,#uid, GETUTCDATE());
SET #lhid = SCOPE_IDENTITY();
INSERT INTO UsersLogOnHistory (explicit columns here)
VALUES(NULL,#uid, #lhid);
Note that you could also do the last bits with an INSERT trigger on LogonHistory, or via OUTPUT.
The number of round trips here: 1
If it was me i would put all that logic in a stored procedure, it's more easy to test and makes for better decoupling.
CREATE PROC logon
#username NVARCHAR(MAX)
, #password NVARCHAR(MAX)
, #IsAuthorized BIT OUTPUT
AS
BEGIN
SELECT #UID = UserId
FROM Users
WHERE Username = #username
AND userPasswordHash = CHECKSUM(#password);
UPDATE Users
SET IsOnline = 1
WHERE UserId = #UID;
INSERT INTO LogonHistory
VALUES(NULL,#UID,GETDATE());
INSERT INTO UsersLogOnHistory
VALUES(NULL,#UID,SCOPE_IDENTITY());
IF #UID IS NOT NULL
SET #IsAuthorized = 1;
ELSE
SET #IsAuthorized = 0;
END;
PS: please be considered for you colleagues privacy and hash their passwords.

Inserting the max value of one comlumn from one table to another table

I am updating a database with a new registered user. they will then be given a userid. I want to use that number when updating there location in another table. but i dont know what the user id will be. (it is autoincrement number) So i was thinkning i would update the first table. And then select the maximum user id and insert that id as the location user id in the other table but I cant get it to work.
Here is the code.
String StrSQL = "INSERT INTO Fastelejer (Fornavn,Efternavn) VALUES ('" + fornavn + "','" +
Efternavn + "')";
OleDbCommand InsertCommand = new OleDbCommand(StrSQL, conn);
InsertCommand.ExecuteNonQuery();
StrSQL = "INSERT INTO Bådpladser (Fastelejerid) SELECT MAX (Fastelejerid) FROM
StrSQL = "INSERT INTO Bådpladser (Fastelejerid) SELECT MAX (Fastelejerid)FROM
Fastelejer WHERE Pladsnummer = " + Pladsnummer;
The pladsnummer represents the input for their location. So the registration should put the user id into the location that is chosen.
In MS Access, "autoincrement" is usually called "identity". You can use the special ##IDENTITY variable to retrieve the ID of the last inserted identity column. Once you know the new ID, you can add it as a parameter in the second insert, like:
command.CommandText = "INSERT Table1 (...) values (...); SELECT ##IDENTITY";
var identity = (int) command.ExecuteScalar();
command.CommandText = "INSERT Table2 (user_id, ...) VALUES (#user_id, ...)";
command.Parameters.AddWithValue("#user_id", identity);
command.ExecuteNonQuery();

Checking for Primary Key assignment

I have a web application that writes to several databases for tracking employee change requests. I am running into a problem with entering in a new employee. They are first written to main Employee database before their access information is written to the other databases with EMP_ID being the primary key. When it goes to write to the other databases EMP_ID has been generated yet so it is getting entered in as 0.
To resolve this I was trying to loop and check the EMP_ID value until a value is generated but I continue to get stuck in a loop because the query returns back that no value was found.
while (int.Parse(empIDChecker) == 0)
{
dbConnection.Open();
validateIDSQLString = "SELECT EMP_ID FROM EMPLOYEE_TABLE WHERE FIRST_NAME = '" + firstNameTextBox.Text.Trim() + "' AND LAST_NAME = '" + lastNameTextBox.Text.Trim() + "'";
SqlCommand updateSQLCmd = new SqlCommand(validateIDSQLString, dbConnection);
SqlDataReader getRecords = updateSQLCmd.ExecuteReader();
try
{
empIDChecker = getRecords["EMP_ID"].ToString();
}
catch
{
empIDChecker = "0";
}
getRecords.Close();
dbConnection.Close();
}
OK, so if your insert sproc looks something like:
sp_InsertEmp
...
INSERT INTO Emp(Name, etc...)
VALUES ('Paul', etc...)
SELECT SCOPE_IDENTITY() AS EMP_ID
GO
And in your code:
SqlCommand insertCmd = new SqlCommand("sp_InsertEmp", dbConnection);
... Add parameters here and set type to StoredProcedure
SqlDataReader dr= insertCmd.ExecuteReader();
int newId;
if (dr.Read())
{
newId = dr.GetInteger(0);
}
you can use
SELECT IDENT_CURRENT(‘tablename’)
This will give you the last inserted auto increment ID of the table, you can use that to insert in other table
Check this link as well http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/

asp.net SQL Server insert statement tidyup + error

I have a form which inserts data into a database.
There are certain fields that are not always going to be needed.
When I leave these blank in my code I get a error saying.
Column name or number of supplied values does not match table
definition.
This is how I have the database setup. SQL Server 2008
[youthclubid]
[youthclubname]
[description]
[address1]
[address2]
[county]
[postcode]
[email]
[phone]
Here is the code that I have connecting to the database and doing the insert.
connection.Open();
cmd = new SqlCommand("insert into youthclublist values ('" + youthclubname.Text + "', '" + description.Text + "','" + address1.Text + "','" + address2.Text + "', '" + county.Text + "', '" + postcode.Text + "', '" + email.Text + "', '" + phone.Text + "')", connection);
cmd.ExecuteNonQuery();
You have two major problems:
1) concatenating together your SQL statement is prone to SQL injection attacks - don't do it, use parametrized queries instead
2) You're not defining which columns you want to insert in your table - by default, that'll be all columns, and if you don't provide values for all of them, you'll get that error you're seeing.
My recommendation: always use a parametrized query and explicitly define your columns in the INSERT statement. That way, you can define which parameters to have values and which don't, and you're safe from injection attacks - and your performance will be better, too!
string insertStmt =
"INSERT INTO dbo.YouthClubList(Youthclubname, [Description], " +
"address1, address2, county, postcode, email, phone) " +
"VALUES(#Youthclubname, #Description, " +
"#address1, #address2, #county, #postcode, #email, #phone)";
using(SqlConnection connection = new SqlConnection(.....))
using(SqlCommand cmdInsert = new SqlCommand(insertStmt, connection))
{
// set up parameters
cmdInsert.Parameters.Add("#YouthClubName", SqlDbType.VarChar, 100);
cmdInsert.Parameters.Add("#Description", SqlDbType.VarChar, 100);
.... and so on
// set values - set those parameters that you want to insert, leave others empty
cmdInsert.Parameters["#YouthClubName"].Value = .......;
connection.Open();
cmdInsert.ExecuteNonQuery();
connection.Close();
}
The first major issue is that you are concatenating inputs in the query. This makes your application highly vulnerable to SQL Injection. Do not do this. Use a parametrized query.
The regular syntax for insert statement is like this:
Insert into <TableName> (Col1, Col2...Coln) values (val1, val2...valn)
If you need to insert only a selected set of columns, you need to provide the list of columns you are inserting data into in the column list.
If you do not specify the column list, the indication is that you are inserting data to each one of them.
So you may check for the input and if it is not there, you may omit the respective column.
The other better way is use a stored proc. That will ease out the issue.
This not way to do the code you make use of SqlParameter for this kind of statement.
So your code something like
SqlConnection thisConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["Northwind_ConnectionString"].ConnectionString);
//Create Command object
SqlCommand nonqueryCommand = thisConnection.CreateCommand();
try
{
// Create INSERT statement with named parameters
nonqueryCommand.CommandText = "INSERT INTO Employees (FirstName, LastName) VALUES (#FirstName, #LastName)";
// Add Parameters to Command Parameters collection
nonqueryCommand.Parameters.Add("#FirstName", SqlDbType.VarChar, 10);
nonqueryCommand.Parameters.Add("#LastName", SqlDbType.VarChar, 20);
nonqueryCommand.Parameters["#FirstName"].Value = txtFirstName.Text;
nonqueryCommand.Parameters["#LastName"].Value = txtLastName.Text;
// Open Connection
thisConnection.Open();
nonqueryCommand.ExecuteNonQuery();
}
catch (SqlException ex)
{
// Display error
lblErrMsg.Text = ex.ToString();
lblErrMsg.Visible = true;
}
finally
{
// Close Connection
thisConnection.Close();
}
You need to tell SQL server that which field you want to insert like
insert into youthclublist(youthclubid, youthclubname, ....) values ('" + youthclubname.Text + "', '" + description.Text + "'.....
and you are fine.
Though new into programming, the easiest way i know to insert into a database is to create a "save" stored procedure, which is then called up through your connection string. Believe me, this is the best way.
Another way around is to use LINQ to SQL. i found this much more easier. Follow this steps.
Add a new LINQ to SQL Classes to your project. Make sure the file extension is '.dbml'. Name it your name of choice say "YouthClub.dbml"
Connect your Database to Visual Studio using the Server Explorer
Drag your table to the OR Designer.(I'm not allowed to post images).
You can now save to the Database with this code
//Create a new DataContext
YouthClubDataContext db = new YouthClubDataContext();
//Create a new Object to be submitted
YouthClubTable newYouthClubRecord = new YouthClubTable();
newYouthClubRecord.youthlubname = txtyouthclubname.Text;
newYouthClubRecord.description = txtdescription.Text;
newYouthClubRecord.address1 = txtaddress1.Text;
newYouthClubRecord.address2 = txtaddress2.Text;
newYouthClubRecord.county = txtcounty.Text;
newYouthClubRecord.email = txtemail.Text;
newYouthClubRecord.phone = txtphone.Text;
newYouthClubRecord.postcode = txtpostcode.Text;
//Submit to the Database
db.YouthClubTables.InsertOnSubmit(newYouthClubRecord);
db.SubmitChanges();
Hope this time I have given a real answer

Categories