I'm trying to insert some data into a MySQL database using the below C# code. If I run this command it throws an exception like the following:
some error: You have an error in your SQL syntax; check the manual that correspo
nds to your MySQL server version for the right syntax to use near ': The Third Reich,
,
' at line 25
Is there a syntax error somewhere? I can't find anything wrong.
var rowContent = String.Format(#"
INSERT INTO animes
(
`JapanTitle`,
`AmericanTitle`,
`GermanTitle`,
`AnimeType`,
`CoverPath`,
`Episodes`,
`MinutesPerEpisodes`,
`JapanStatus`,
`AmericanStatus`,
`GermanStatus`,
`JapanTimeSpan`,
`AmericanTimeSpan`,
`GermanTimeSpan`,
`MainGenres`,
`SubGenres`,
`JapanStudios`,
`AmericanStudios`,
`GermanStudios`,
`GermanDescription`,
`EnglishDescription`)
VALUES
({0},
{1},
{2},
{3},
{4},
{5},
{6},
{7},
{8},
{9},
{10},
{11},
{12},
{13},
{14},
{15},
{16},
{17},
{18},
{19});", entity.JapanTitle,
entity.AmericanTitle,
entity.GermanTitle,
entity.AnimeType.ToString(),
entity.WallPaper.FileName,
entity.Episodes,
entity.MinutesPerEpisode,
entity.JapanStatus.ToString(),
entity.AmericanStatus.ToString(),
entity.GermanStatus.ToString(),
entity.JapanTimeSpan.ToString(),
entity.AmericanTimeSpan.ToString(),
entity.GermanTimeSpan.ToString(),
string.Join(",", entity.MainGenres),
string.Join(",", entity.SubGenres),
string.Join(",", entity.JapanStudios),
string.Join(",", entity.AmericanStudios),
string.Join(",", entity.GermanStudios),
entity.GermanDescription,
entity.EnglishDescription);
If I look at this code, I think it is pretty bad code. Is there a better way to insert many columns into a database without something like the entity framework?
Your main error is caused by the missing quotes around your strings. In a sql command text, when you want to pass a value for a text field you need to put this value between single quotes.
But also with appropriate quotes around your values you have another big problem called Sql Injection.
The only secure way to use a command like that is through a parameterized query.
Something like this (I will cut your code because is too long)
string cmdText = #"INSERT INTO animes
(JapanTitle,AmericanTitle,GermanTitle,AnimeType,.....)
VALUES(#japtitle, #usatitle, #germantitle, #animtype, ....)";
MySqlCommand cmd = new MySqlCommand(cmdText, connection);
cmd.Parameters.AddWithValue("#japtitle", entity.JapanTitle);
cmd.Parameters.AddWithValue("#usatitle", entity.AmericanTitle);
cmd.Parameters.AddWithValue("#germantitle", entity.GermanTitle);
cmd.Parameters.AddWithValue("#animtype", entity.AnimeType);
....
cmd.ExecuteNonQuery();
In this way you don't write directly the values in the command text, but put placeholders for the parameters value. It is the database engine that will figure out how to use the parameters passed along the command. (And no need to worry about quotes around your string or escape quotes that are part of your values)
Notice also that the AddWithValue method of the Parameters collection has its own quirks. You need to pass the value with the exact datatype expected by the database field (So, no ToString() for AnimeType if the field expects an integer)
First of all, your database should probably look something like this:
An animes table with non-language values like CoverPath, Episodes, etc. - one row per movie
An animes_lang table with language-specific values like Title, Status, TimeSpan, Studios, etc. - one row per language per movie
That would probably make it easier to maintain.
At any rate, I can make the query construction a little easier but you'll need to specify all of the parameters.
String[] cols = {
"JapanTitle",
"AmericanTitle",
"GermanTitle",
"AnimeType",
"CoverPath",
"Episodes",
"MinutesPerEpisodes",
"JapanStatus",
"AmericanStatus",
"GermanStatus",
"JapanTimeSpan",
"AmericanTimeSpan",
"GermanTimeSpan",
"MainGenres",
"SubGenres",
"JapanStudios",
"AmericanStudios",
"GermanStudios",
"GermanDescription",
"EnglishDescription"
};
String query =
"INSERT INTO animes (" + String.Join(", ", cols) +
") VALUES (" + String.Join(", #", cols) + ");";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("#JapanTitle", entity.JapanTitle);
cmd.Parameters.AddWithValue("#AmericanTitle", entity.AmericanTitle);
cmd.Parameters.AddWithValue("#GermanTitle", entity.GermanTitle);
. . .
cmd.Parameters.AddWithValue("#EnglishDescription", entity.EnglishDescription);
cmd.ExecuteNonQuery()
Please use Steve's answer or this one. Don't go the String.Format route. It may be that SQL Injection isn't a worry here, but make a habit of doing this the safe and right way.
Related
I tried to search a lot for tutorials on Npgsql and c#. but I couldn't resolve the below problem.
When I run the program, my programs stop and breaks at execute query. and when I try debug and check the return value from the execute reader is empty.
below is the sample code:
string user=textBox1.Text;
NpgsqlConnection dataconnect = new NpgsqlConnection(
"Server=127.0.0.1;Port=5432;User Id=dbuser;Password=dbpass;Database=dbname;");
string query = "Select USERNAME from helperdata.credentials where USERNAME = "
+ textBox1.Text + " and PASSWORD = " + textBox2.Text;
dataconnect.Open();
NpgsqlCommand command = new NpgsqlCommand(query, dataconnect);
NpgsqlDataReader reader = command.ExecuteReader();
if(reader.Read())
{
MessageBox.Show("Login Successful");
}
else
{
MessageBox.Show("Login failed");
}
reader.Close();
dataconnect.Close();
When I try to run the below query in Pgsql it returns the data.
Select "USERNAME" from helperdata.credentials where "USERNAME" = 'admin'
I am new to Npgsql.
I would also like if someone could provide me some good tutorial sites which provides detail explanation of Npgsql and C#.
Thanks in advance.
I have identified two problems in your code. The first the usage of uppercase letters on PostgreSQL identifiers. PostgreSQL allows identifiers with other than simple lowercase letter, but only if you quote them.
In fact, you can use, for instance:
CREATE TABLE helperdata.credentials (... USERNAME varchar, ...);
But PostgreSQL will convert it to:
CREATE TABLE helperdata.credentials (... username varchar, ...);
So, to make it really left with uppercase, you have to quote it as following:
CREATE TABLE helperdata.credentials (... "USERNAME" varchar, ...);
And that seems to be the way you have created your table, and the problem with that is that always you refers to that table in a query, you'll have to quote it. So the beginning of your query should be:
string query = "Select \"USERNAME\" from helperdata.credentials ... ";
My recommendation, is to modify your column and table names to don't use such identifiers. For this case you can do:
ALTER TABLE helperdata.credentials RENAME COLUMN "USERNAME" TO username;
The second problem, is the lack of string quotation when you concatenated the username from the textbox into the query. So, you should do something as the following (BAD PRACTICE):
string query = "Select \"USERNAME\" from helperdata.credentials where \"USERNAME\" = '"
+ textBox1.Text + "' and \"PASSWORD\" = '" + textBox2.Text + "'";
There is a huge problem with that, you can have SQL injection. You could create a function (or use one from Npgsql, not sure if there is) to escape the string, or, more appropriately, you should use a function that accept parameters in the query using NpgsqlCommand, which you can simple send the parameters or a use a prepared statement.
Check the Npgsql documentation, and find for "Using parameters in a query" and "Using prepared statements" to see examples (there are no anchors in the HTML to link here, so you'll have to search).
Suppose that I want to create an SQL SELECT statement dynamically with reflection on primary key. I search in the table for primary keys and then, I make the statement.
Problem is, I don't know the type of fields that compose the primary key before getting them. So, if it's a string or date, I must add quotation marks but not if it's an int.
Atm, I am doing like that :
var type = field.GetType().Name;
if (type.ToLower().StartsWith("string") || type.ToLower().StartsWith("date"))
{
field = "\"" + field + "\"";
} else if (type.ToLower().StartsWith("char"))
{
field = "\'" + field + "\'";
}
With this code, I can handle some SQL types but there are a lot more.
My problem is that it's combined with LinQ. I got a DataContext object and a generic type table from the context. And context.ExecuteQuery only allows parameters to be passed has values. I also tried with Dynamic LinQ but I got the same problem
Does anyone know a better solution?
That is simply the wrong way to write SQL. Parameterize it and all these problems evaporate (as do problems with "which date format to use", etc. And of course the biggie: SQL injection.
Then it just becomes a case of adding #whatever into the TSQL, and using cmd.Parameters.AddWithValue("whatever", field) (or similar).
Update (from comments): since you mention you are using DataContext.ExecuteQuery, this becomes easier: that method is fully parameterized using the string.Format convention, i.e.
object field = ...;
var obj = db.ExecuteQuery<SomeType>(
"select * from SomeTable where Id = {0}", field).ToList(); // or Single etc
No string conversions necessary.
(the last parameter is a params object[], so you can either pass multiple discreet terms, or you can populate an object[] and pass that, if the number of terms is not fixed at compile-time; each term in the array maps by (zero-based) index to the {0}, {1}, {2}... etc token in the query)
Have you tried with parameters? For instance if you are using SQLServer as a database and you want to do this query:
"SELECT * FROM someTable WHERE id = " + field;
Then you should use sometething like this:
"SELECT * FROM someTable WHERE id = #field"
and add parameter to your command:
SqlParameter param1 = new SqlParameter("#field", field);
command.Parameters.Add(param1);
EDIT: Watch out that for different database providers the syntax for the SQL query is different, the same for the Access would be
"SELECT * FROM someTable WHERE id = ?";
command.Parameters.AddWithValue("field", field);
I have this program that is feeding me data. I take this data (string) and parse it so that the different fields can go into the respective db table column. I can parse the string but I can't find the right function or way to send them to the db. This is my second time working with sql server or database in general. I have done inserts this way
MyCommand.CommandType = System.Data.CommandType.Text;
MyCommand.CommandText = "INSERT INTO TimeStampTable(ID, TimeStamp) VALUES ('24', 'sep 13, 2009')";
From what I know, CommandType only allows either text or a stored procedure. In this case, I would want to insert the string that is being parsed.
string teststring = dtString;
string[] result = teststring.Split(',', ' ', ':', '=');
Console.WriteLine("The parsed string looks like this:");
foreach (string word in result)
{
Console.WriteLine(word);
}
This is my code that parses my incoming string. So I receive name address zip state, etc. I would like for name to go to col1, address to go to col2, etc. I think the ideal way to do this would be to convert my loop to something like this
foreach (string word in result)
{
SqlDatasource.InsertCommand=Insert into Tablename col1 col2 col3(word);
}
Does anyone have any suggestions?
I will answer your question directly, but there are many different ways that you could go about performing the same thing (I will list some at the end)
String insertQuery = "INSERT INTO TABLENAME (Col1, Col2, Col3...) VALUES (";
//This is also assuming that your data is in the same order as the columns
int isFirstLoop = true
foreach(string word in result)
{
if(!isFirstLoop)
insertQuery += ","
insertQuery += word;
isFirstLoop = false;
}
insertQuery += ")";
SqlDataSource.InsertCommand = insertQuery;
NOTE: this is very open to SQL Injection, so keep that in mind (do you trust your incoming source). There are ways to clean the data, but ultimately, I suggest some of the methods listed below
Alternatives:
Use a stored procedure over direct TSQL. Then you can map your data to SQLParameters, which (I believe) are built to scrub the data to protect against SQL Injection
Use a very basic ORM and/or LINQ so that you can work with objects directly. Then you only need to read the data into a POCO
I am sure there are other ways, however for some reason I am drawing a blank. I think that is because these are the most used alternatives :)
I have the following code in asp.net:
using (OleDbCommand command = dbConnW.CreateCommand())
{
string CreateTableK = null;
CreateTableK += "Create Table DSKKAR00 (DSK_ID c(10),DSK_KIND N(1),MON_PYM C(3))";
OleDbCommand cmdCreateTable = new OleDbCommand(CreateTableK, dbConnW);
cmdCreateTable.ExecuteNonQuery();
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append(WorkRoomNo + ",");
sb.Append("1,");
sb.Append(",");
OleDbCommand cmd3 = new OleDbCommand("Insert into DSKKAR00 (DSK_ID,DSK_KIND,MON_PYM) Values (" + sb.ToString() + ")", dbConnW);
cmd3.ExecuteNonQuery();
But I have the following error:
Syntax error
In addition to what Chris has offered, you are starting your CREATE TABLE with a NULL string variable, then doing a += to it. From what I remember, a NULL += "anystring" will remain a null value... You might be crashing right there too.
Although VFP is not really suceptible to SQL Injection like other SQL engines, its good habit to do parameterizing. When you do, use "?" as a place-holder for the value you want to insert, and add parameters in the same order sequence as the "?" represent.
string CreateTableK =
"Create Table DSKKAR00 (DSK_ID c(10),DSK_KIND N(1),MON_PYM C(3))";
OleDbCommand cmdCreateTable = new OleDbCommand(CreateTableK, dbConnW);
cmdCreateTable.ExecuteNonQuery();
string MyInsert =
"insert into DSKKAR00 ( dsk_id, dsk_kind, mon_pym ) values ( ?, ?, ? )";
OleDbCommand cmd3 = new OleDbCommand( MyInsert, dbConnW);
cmd3.Parameters.AddWithValue( "parmSlot1", WorkRoomNo );
cmd3.Parameters.AddWithValue( "parmSlot2", 1);
cmd3.Parameters.AddWithValue( "parmSlot3", 'tst' ); // or whatever variable to put
cmd3.ExecuteNonQuery();
First off, any time you have an error it's usually best to post the entire error message you get.
Also, when trying to debug a query problem, you should emit the actual query being sent to your server/database and inspect it. This way you can find various problems like too many commas.
Speaking of which, looking at your code, you are concatenating a String and it really looks like you have way too many commas.
The emitted query looks like it will be:
insert into DSKKAR00(DSK_ID, DSK_KIND, MON_PYM) VALUES( X,1, ,)
where X is the value of your WorkRoomNo variable.
Obviously, that isn't valid syntax and would result in the error you've seen. The commas indicate there are 4 values being passed, but the insert query only identifies 3 columns.
The next issue has to do with the column definitions themselves. The first column of that table is a c(10); the third is a c(3). I'm a little rusty, but aren't those character fields?
If so then you need to adjust your string builder to add the appropriate quotes around the values...
Which leads us to the final problem: Don't use String concatentation to build queries. Use Parameterized queries
I am trying to insert string as "baby's world" into the column of type varchar through query but shows me error.
Is there anything else i need to put to the query so that it accept that symbol
put a backslash in front of it like so:
"Baby\'s world"
You can find and replace them in your string using the following:
str.Replace('\'', '\\\'')
I'm not 100% sure about this last part, but you need to 'escape' the ' and \ by adding a \ in front of it. So it would seem alright (can't test as i'm not a C# programmer.
Since you are asking about Visual Studio (.NET), you need to use parameterized query. Don't use concatenation when constructing query
private void PrepareExample()
{
string s = Console.ReadLine();
MySqlCommand cmd = new MySqlCommand("INSERT INTO movie(title) VALUES (?title)", myConnection);
cmd.Parameters.AddWithValue( "?title", "baby's world" );
cmd.Prepare();
cmd.ExecuteNonQuery();
}
Or
private void PrepareExample()
{
MySqlCommand cmd = new MySqlCommand("INSERT INTO movie(title) VALUES (?title)", myConnection);
// try to input: baby's world. or try: baby"s world. everything are ok :-)
cmd.Parameters.AddWithValue( "?title", Console.ReadLine() );
cmd.Prepare();
cmd.ExecuteNonQuery();
}
Though this is not exactly concatenation, don't use this:
qry = string.Format("INSERT INTO movie(title) VALUES("{0}", Console.ReadLine());
Though if you really found a need to run SQL that way, replace single quote with backslash
qry = string.Format("INSERT INTO movie(title) VALUES("{0}",
Console.ReadLine().Replace("'", "\'");
But do consider using parameterized query instead of concatenation or string.Format, as parameterized query automatically take care of those delimeter nuances.
http://dev.mysql.com/doc/refman/5.0/es/connector-net-examples-mysqlcommand.html
Just use mysql_real_escape_string(). There is no need to do anything else.
For example:
mysql_real_escape_string($user),
mysql_real_escape_string($password));
INSERT INTO table (field) VALUES ('baby's world') will fail because the string is truncated to INSERT INTO table (field) VALUES ('baby' and the rest is seen as invalid code.
There are two ways to stop this, the second being advisable for good practice coding:
INSERT INTO table (field) VALUES ("baby's world")
INSERT INTO table (field) VAUES ('baby\'s world')