Insert data into SQL database using Where clause - c#

How can you add data to a specific row in a database, using the where clause.
Here is what I tried:
"Insert into table1 (name, address) values ('" + textbox1.Text+ "', '"+textbox2.Text+"')
where (name ='"+textbox1.Text+"')"

Firstly, never ever concatenate strings for database input. It leaves you wide open to SQL Injection attacks. See this MSDN article for more information
Secondly, you don't do inserts with a WHERE clause. You could do an UPDATE with a WHERE
Examples:
INSERT INTO TABLE (col1, col2) VALUES (val1, val2)
UPDATE TABLE SET col1 = val1, col2 = val2 WHERE col3 = somevalue
for example in your case, you would want to write this for an insert (including parameters)
sql = "INSERT INTO table1 (name, address) VALUES (#textbox1,#textbox2)";
SqlCommand query = new SqlCommand("connection string", sql);
query.Parameters.AddWithValue(#textbox1, textbox1.Text);
query.Parameters.AddWithValue(#textbox2, textbox2.Text);
If you know the database field type, instead of using AddWithValue, instead use this syntax:
query.Parameters.Add(#parametername, SqlDBType.Type,size).Value = somevalue;
where SqlDBType.Type is the database field type (eg VarChar, Int, VarBinary etc) and size is the value of the field. If my DB field was VarChar(500), then my parameter setup would be
query.Parameters.Add(#parametername, SqlDBType.VarChar, 500).Value = somevalue;
you can replace the sql string with the following if you want to update rather than insert. Note, update records using an identifier - it would be a bad practice to use name as your WHERE clause.
sql = "UPDATE table1 SET name = #textbox1, address = #textbox2 WHERE xyz";
Parameters prevent users from putting unexpected values into boxes allowing for unauthorised code to be run. Using a concatenated string as you currently are could enable an attacker to compromise your entire database

you can't insert with a 'where' clause inseert is for adding new records. If your updating then use:
Update table1 set
name = '" + textbox1.Text + "',
address ='" + textbox2.Text+ "'
where (name ='"+textbox1.Text+"')
or insert should be:
"Insert into table1 (name, address) values ('" + textbox1.Text+
"','"+textbox2.Text+"')"
however make sure everything is validated against sql injection. or parameterize the above.

You don't need a where clause for inserting a record into SQL Server database using INSERT statement. You should change your code as below to make it work:
"Insert into table1 (name, address) values ('" + textbox1.Text+ "', '"+textbox2.Text+"')
Two possible forms of a SQL insert statement are as below:
INSERT INTO table_name (column1,column2,column3,...)
VALUES (value1,value2,value3,...);
INSERT INTO table_name
VALUES (value1,value2,value3,...);
You can learn more about INSERT SQL statement here:
http://www.w3schools.com/sql/sql_insert.asp

Related

How to use every word of a string in WHERE clause?

I am facing a problem , I have a query in SQL Server 2014, The query result should be based on a WHERE clause that takes a string from a C# CheckedListBox.
I have the string in this form (the following values are for example only) :-
cat,dog,bird,duck
And inside the database the records look like this:-
dog cat-dog cat-dog-duck bird-dog-duck etc...
I have tried this :-
DECLARE #animals nvarchar(max) = 'dog,bird,cat'
select x,y,z WHERE CHARINDEX(animals, replace(#animals,',',' ')) > 0
The result would show rows with only ONE SINGLE VALUE like dog cat bird But it wouldn't show rows with values like dog-cat dog-cat-bird etc! it just shows rows with one single word from #animals string.
How can I select all rows where column animals contains either a word or more from #animals string.
Thanks in advance...
You should create a temp table for store all searching value or you should create a temp table from the comma separated variable for the example visit Query for convert CSV values into temp table. Then use inner join for filter records from your table like below.
declare #temp table (animal varchar(50))
insert into #temp values ('cat')
insert into #temp values ('dog')
insert into #temp values ('bird')
select * from SomeTable a
inner join #temp t on a.Column like '%' + t.animal + '%'
Make stored procedure for that query and call it from C#.
And inside the database the records look like this:-
dog cat-dog cat-dog-duck bird-dog-duck etc...
There is the source of your problems. Before reading anything else I wrote in my answer, you should read Is storing a delimited list in a database column really that bad?, where you will see a lot of reasons why the answer to this question is Absolutely yes!.
Once you're done with that, the solution to the problem should be as obvious to you as it is to me - Fix the database structure - meaning remove that column storing delimited data and replace it with a table referenced by a many-to-many relationship to your existing table, that will hold the animals data for you.
The first part of the solution is using a table valued parameter instead of sending a delimited string to the database.
There are plenty of examples on how to do this on stackoverflow - like here and there.
Once you've done that, you can use a hack with like as a workaround, in case you can't change the database structure:
SELECT <ColumnsList>
FROM <TableName> As T
JOIN #TVP As TVP
ON '-' + T.Animals +'-' LIKE '%-' + TPV.Animal +'-%'
Note I've added the delimiter to both ends of both columns.
If you can change the structure you will have a query like this:
SELECT <ColumnsList>
FROM <TableName> As T
JOIN TableToAnimals AS TTA
ON T.Id = TTA.TableId
JOIN Aniamls AS A
ON TTA.AnimalId = A.Id
JOIN #TVP As TVP
ON A.Name = TVP.Animal
You should take a look at Table valued parameters, it will let you send in a table of values as a parameter from C# to SQL. You make a table with "animals" and then make a sub-select in your Stored Proc.
See example code from link below, shows how to pass the parameter:
// Assumes connection is an open SqlConnection object.
using (connection)
{
// Create a DataTable with the modified rows.
DataTable addedCategories = CategoriesDataTable.GetChanges(DataRowState.Added);
// Configure the SqlCommand and SqlParameter.
SqlCommand insertCommand = new SqlCommand("usp_InsertCategories", connection);
insertCommand.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue("#tvpNewCategories", addedCategories);
tvpParam.SqlDbType = SqlDbType.Structured;
// Execute the command.
insertCommand.ExecuteNonQuery();
}
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql/table-valued-parameters
For anyone who has the same problem. I have found the solution for this on SQL Server. Use the Full Text Search and your problem is easily solved. It's awesome.
Check the following link :-
https://learn.microsoft.com/en-us/sql/relational-databases/search/get-started-with-full-text-search?view=sql-server-2017
use like this:
var query = string.Empty;
var index=0;
foreach(var animal in animals) {
if (query.Length>0) {
query +=" and ";
}
var paramName = "#animalName" + index++;
query +="(animals like " + paramName + " or animals like '%' + " + paramName + " or animals like " + paramName + " + '%' or animals like '%' + " + paramName + " + '%')";
SqlParameter thisParam = new SqlParameter(paramName, animal);
command.Parameters.Add(thisParam);
}
command.CommandText = "select * from tableName WHERE " + query;

How create a row and take his id at the same time in sql server and c#

I'm having a simple problem but cant find a solution:
I'm creating a row in my table client, but I don't know how recovery the id of the table that I just created, for example:
ALTER proc [dbo].[spinsert_client]
#idclient int output,
#name varchar(20),
#surname varchar(40),
as
insert into client(name,surname)
values (#name,#surname)
here I insert a client, now I want recovery that exact same idclient to insert "products" with it without have to manually search this client , I tried recovering the last row of the client table but I realise that if more than one person is using the same database in different computers it can be a problem, so I need create a client and recovery his id at the same time (it is an assumption I don't know). Im using sql server and Visual studio with c#
sorry for my bad English and thanks for the attention
edit-------------------
solution:
ALTER proc [dbo].[spinsert_client]
#idclient int output,
#name varchar(20),
#surname varchar(40)
as
insert into client(name,surname)
values (#name,#surname)
Select ##IDENTITY as newId;
them in my c# code:
rpta= SqlCmd.ExecuteScalar().ToString();
The best way is to use the OUTPUT clause. Here is an example that just captures the new id:
ALTER proc [dbo].[spinsert_client] (
#idclient int output,
#name varchar(20),
#surname varchar(40)
)
as
begin
declare #output table (idclient int);
insert into client(name, surname)
output inserted.idclient into #output;
values (#name, #surname);
select *
from #output;
end; -- spinsert_client
In your C# code you have somewhere a sql Statement defined:
string sqlStatement = "INSERT INTO ... (field list) OUTPUT INSERTED.yourfieldwithid values (value list) ";
and use it with ExecuteScalar() for getting the result value (I assume you know how to use Connection and command object)
You can do this:
string query = "INSERT INTO client" +
" (name, surname)" +
" VALUES (#Name, #Surname);" +
" SELECT SCOPE_IDENTITY();";
using (var dbconn = new SqlConnection("your connection string here") )
using (var dbcm = new SqlCommand(query, dbconn) )
{
dbcm.Parameters.Add("#Name", SqlDbType.VarChar, 20).Value = "name value";
dbcm.Parameters.Add("#Surname", SqlDbType.VarChar, 40).Value = "surname value";
dbconn.Open();
var insertedID = (int)dbcm .ExecuteScalar();
}
Check this SO post explaining every way of retrieving the inserted id from the table.
To answer your question, both OUTPUT_CLAUSE and IDENT_CURRENT can be used in this scenario but i would recomment IDENT_CURRENT because an OUTPUT clause will return rows to the client even if the statement encounters errors and is rolled back.
Use it like:
using (SqlCommand com = new SqlCommand("INSERT INTO cient(name, surname)"+
"VALUES (#Name, #Surname) SELECT IDENT_CURRENT('client'); ", con))
I would not suggest SCOPE_IDENTITY or ##IDENTITY because it may return wrong values (null) if you're not using SQL Server 2008 R2 SP2 or higher ( source - last row from the page.) especially for your requirement (inserting the value in some other table).

how to write data to mysql database and ignore a column using c#

I have a C# program that connects to a remote mysql server and store date in a database on it.
In my db I have a column which I need it to have the CURRENT_TIMESTAMP of the server so I set the type of the column in my db to timestamp and the default value to CURRENT_TIMESTAMP the problem is when I ignore this column in my command I get this error "column count doesn't match value count at row 1" and if I send empty value, the value in the db becomes like this "0000-00-00 00:00:00".
here is my code
DBConnectMySQL.DBCommand.CommandText =
"INSERT INTO tbCard VALUES (#id,#Phone, #username, #CardDate)";
DBConnectMySQL.DBCommand.Parameters.AddWithValue("#id", "");
DBConnectMySQL.DBCommand.Parameters.AddWithValue("#Phone", number);
DBConnectMySQL.DBCommand.Parameters.AddWithValue("#username", UserName);
DBConnectMySQL.DBCommand.Parameters.AddWithValue("#CardDate", ""); // here is the problem
DBConnectMySQL.DBCommand();
DBConnectMySQL.DBCommand.Parameters.Clear();
I don't want to send the current time and date of the machine because I want to use the server time.
Specify which columns you want to insert and omit the column:
DBConnectMySQL.DBCommand.CommandText = "INSERT INTO tbCard(id, Phone, username) VALUES (#id,#Phone, #username)";
DBConnectMySQL.DBCommand.Parameters.AddWithValue("#id", "");
DBConnectMySQL.DBCommand.Parameters.AddWithValue("#Phone", number);
DBConnectMySQL.DBCommand.Parameters.AddWithValue("#username", UserName);
If you use an INSERT statement without saying which columns receives the values then you need to pass all the values for all the columns in the order in which the columns are defined in the table.
To avoid this problem just specify the column's names before the VALUES statement
string cmdText = #"INSERT INTO tbCard (col1, col2, col3)
VALUES (#id, #Phone, #username)";
DBConnectMySQL.DBCommand.CommandText = cmdText;
Also, if the ID column is an AUTO-INCREMENT column, then you shouldn't pass also this column and its value.

Converting Stored Procedure into a query (SQL Server Compact)?

I'm trying to convert the following stored procedure into a query, so that I can use it in SQL Server CE
USE TestResults
GO
CREATE PROCEDURE uspInsertNewTest
(#DeviceSerialNumber nvarchar(50),
#DeviceType nvarchar(50),
#ElapsedTime int)
AS
BEGIN
INSERT INTO [TestResults].[dbo].[Tests]([Date], [Device], [DeviceType], [ExecutionTimeMs])
OUTPUT INSERTED.TestId
VALUES (GETDATE(), #DeviceSerialNumber, #DeviceType, #ElapsedTime)
END
GO
From the above script, all I can understand is that it takes three input parameters
DeviceSerialNumber
DeviceType
ElapsedTime
but it'll update 5 columns in the table Tests including Date and TestId.
Since I can't use stored procedures in SQL Server CE, I've converted the above script into a string query,
string queryString = "INSERT INTO Tests ([Date], [Device], [DeviceType], [ExecutionTimeMs]) VALUES (#Date, #DeviceSerialNumber, #DeviceType, #ElapsedTime)"
Now how to include OUTPUT INSERTED.TestId into the string( queryString ) ?
There's a similar question here, but it doesn't help my problem
Thanks!
You can use ##IDENTITY to return the last inserted identity value:
string queryString = "INSERT INTO Tests " +
"([Date], [Device], [DeviceType], [ExecutionTimeMs]) " +
"VALUES (#Date, #DeviceSerialNumber,#DeviceType, #ElapsedTime); " +
"SELECT ##IDENTITY;"
When you execute your query, you need to set it up to return a single value using the ExecuteScalar method:
var newIdentity;
// set up the queryString variable & command using the above
newIdentity = cmd.ExecuteScalar();
This assumes that the column TestId is an identity column.
Though I accepted Tanner's answer, but I ended up doing like this,
string queryString = "INSERT INTO Tests " + "([Date], [Device], [DeviceType], [ExecutionTimeMs]) " +
"VALUES (#Date, #DeviceSerialNumber,#DeviceType, #ElapsedTime)";
string queryString2 = "SELECT ##IDENTITY";
DbCommand command = factory.CreateCommand ();
command.CommandText = queryString;
// Added Parameters here
command.ExecuteNonQuery ();
command.CommandText = queryString2;
object testId = command.ExecuteScalar ();
So I had to split the query into two string & run ExecuteNonQuery with the first string and run ExecuteScalar with the second string.

C# Alter Table and Add a column programmatically ASP.Net & SQL Server

I have been trying to add a column programmatically in ASP.NET to modify the tables in SQL Server.
Please see the following code:
string suppliernotxt = supplieridlist[1].ToString();
//SqlCommand cmd2 = new SqlCommand("ALTER TABLE [ProductNormalDB] ADD suppliernotxt nvarchar(20) NULL", con);
SqlCommand cmd2 = new SqlCommand("ALTER TABLE ProductNormalDB ADD #supplierlist nvarchar(20) NULL", con);
cmd2.Parameters.AddWithValue("#supplierlist", suppliernotxt);
//cmd2.Parameters.AddWithValue("#supplierlist", suppliernotxt.ToString());
//cmd2.Parameters["#supplierlist"].Value = supplieridlist[x];
cmd2.ExecuteNonQuery();
supplieridlist is an array that acquires all the column names to add into the SQL Server database. For some reason the parametrized method is not working and shows the following error:
Incorrect syntax near '#supplierlist'.
The basic idea is to have a user select from a check box the name of the suppliers, based on the selected number of suppliers the array will create the supplier names for ex. if we selected 3 suppliers, the array will save "Supplier1", "Supplier2", "Supplier3" and then the SqlCommand is supposed to alter the table and add the new columns.
You cannot use parameters to express the name of columns.
Parameters could only be used to express values for WHERE clause or for INSERT or UPDATE statements.
You could use string concatenation for your query text, passing the string value to a stored procedure or use some form of dynamic sql.
Please be very carefull with these kind of approaches because if you don't keep absolute control on the values passed to your code you will be exposed to Sql Injection.
Adding as an example of Dynamic SQL execution, but still vulnerable to SQL Injection
string suppliernotxt = supplieridlist[1].ToString();
string execSQL = "DECLARE #sup nvarchar(15); " +
"SET #sup = '" + suppliernotxt + "'; " +
"EXEC ('ALTER TABLE ProductNormalDB ADD ' + #sup + ' nvarchar(20) NULL')"
SqlCommand cmd2 = new SqlCommand(execSQL, con);
cmd2.ExecuteNonQuery();
As you can see, even with Dynamic SQL there is nothing that prevent an SQL Injection attack passing via the suppliernotxt variable
EDIT As explained in the comments below from #RBarryYoung, a good improvement on the SQL Injection problem for this case of dynamic sql could be the usage of the QUOTENAME function to obtain an Unicode string with the required delimiters around the input string
string execSQL = "DECLARE #sup nvarchar(15); " +
"SET #sup = QUOTENAME('" + suppliernotxt + "'); " +
"EXEC ('ALTER TABLE ProductNormalDB ADD ' + #sup + ' nvarchar(20) NULL')"

Categories

Resources