I know this question have been asked several times, but none of answers has helped me resolving this issue.
So, i'm writing data transfer utility, copying data from one table of OleDb database to table of another OleDb database.
I have read all the data from the source database, and i'm trying to write, but always gets this error
Must declare the scalar variable "#CategoryID"
Here's the code
// generating the insert string below
string insert = "INSERT INTO Categories VALUES (";
for(int i = 0; i < cols.Length; i++)
{
string coma = ", ";
if (i == cols.Length - 1)
coma = " )";
insert += "#" + cols[i] + coma;
}
try
{
while (src_reader.Read()) // reading from source database
{
dstcmd.CommandText = insert;
for (int i = 0; i < cols.Length; i++)
{
string temp = "#" + cols[i]; // cols is array of column names
dstcmd.Parameters.AddWithValue(temp, src_reader[cols[i]]);
// for debug purposes... below is screenshot of error
Console.Write(temp + " " + src_reader[cols[i]] + "\n");
}
Console.WriteLine("");
// point of error
dstcmd.ExecuteNonQuery();
}
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
Here's the screenshot of error.
CategoryID is the first column of the table and hence the first value that is being inserted.
Any help will be appreciated. If i missed any information or something does not make sense, please do let me know.
Try changing this part:
// generating the insert string below
string insert = "INSERT INTO Categories VALUES (";
for(int i = 0; i < cols.Length; i++)
{
string coma = ", ";
if (i == cols.Length - 1)
coma = " )";
insert += "#" + cols[i] + coma;
}
to
// generating the insert string below
string insert = "INSERT INTO Categories VALUES (";
for(int i = 0; i < cols.Length; i++)
{
string coma = ", ";
if (i == cols.Length - 1)
coma = " )";
insert += "?" + coma;
}
You don't need to use parameter names in VALUES, but just ? placeholders. However, make sure the order of parameters when you add them matches the order of columns in the table.
Also, it may be better to explicitly specify the column list in the INSERT clause, like:
string insert = "INSERT INTO Categories (Col1, Col2, Col3, etc.) VALUES (";
See if you want to make that column names list dynamically generated too. But I suggest to get it working for the static column list first and then convert it to dynamic version.
Also, if you don't specify the column name list for INSERT you will have specify values for all columns.
Related
I need to update a table called Calculated in my database, but because I have so many values that I have stored in my system as variables to add/update in the table, I created a separate table in the database called Database Relationships.
This Database Relationships table has a column called Calculated Value which holds all the field names of the Calculated table. The other column, System Field holds all the names of variables that I have created and given values to, which are of all string type and that relate to the corresponding Calculated Value
So by using a FOREACH loop
OleDbDataAdapter relationshipAdapter = new OleDbDataAdapter(relationshipCmd);
DataTable relationshipTable = new DataTable();
relationshipAdapter.Fill(relationshipTable);
string update = "Update [Calculated] SET ";
int i = 0;
int len = relationshipTable.Rows.Count;
foreach (DataRow drr in relationshipTable.Rows)
{
string calc = drr["Calculated Field"].ToString();
var sys = drr["System Field"].ToString();
if (i == len - 1)
{
update += "[" + calc + "] = " + sys + ";";
}
else
{
update += "[" + calc + "] = " + sys + ", ";
}
i++
}
update += "WHERE [NSN] = '" + NSN + "';";
OleDbCommand updateCmd = new OleDbCommand(update);
But this is not working, because after some debugging(?) I did a simple Console.WriteLine(sys) and it would print out the string in the System Field column, instead of the variable with the same name in the system.
I am currently using Microsoft Access as my database platform.
I think having "intermediate" table for temporary storing values in runtime for future saving in another table sounds little bid complicated for me.
If you want to map variables at runtime with column name in the database - use dictionary for example:
Dictionary<string, string> myValues = new Dictionary<string, string>();
Using in the application:
myValues["SomeColumn"] = "your value";
Then saving data to database will be:
var updateCmd = new OleDbCommand();
var query = new StringBuilder();
foreach(KeyValuePair<string, string> value in myValues)
{
string columnName = value.Key;
query.AppendLine($", {columnName} = ?");
var param = new OleDbParameter("#v", value.Value);
// Name of parameter not important, only order
}
if(query.Length > 0)
{
query.Remove(0, 1); // Remove first ',' character
query.Insert("Update [Calculated] SET ");
query.AppendLine("$WHERE [NSN] = '{NSN}';");
}
updateCmd.CommandText = query.ToString();
Very important: you need to use OleDbParameter for passing values to the query.
In you foreach loop, use this:
if (i == len - 1)
{
update += "[" + calc + "] = " + this.GetType().GetProperty(sys).GetValue(this, null)+ ";";
}
else
{
update += "[" + calc + "] = " + this.GetType().GetProperty(sys).GetValue(this, null)+ ", ";
}
The code above assumes that the variables are scoped in the same scope where you are generating your Sql.
In loop , you use the condition:
if (i == len - 1)
but you never change "len" or "i" value in the code.
I'm trying to update a column in a row with a new value. the new value is in a variable, and the value contain a new line in it.
This method receive as dictionary the column name and values need to change, and create a dynamic update command.
The Code is working for any other row in the table, but when a newline is involved, and SQL Error saying: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near
var valueStr = "";
for (var i = 0; i < srcRow.Count; i++)
{
valueStr += string.Format("{0} = ?prm{1}", srcRow.Keys.ElementAt(i),i);
if (i < srcRow.Count - 1)
valueStr += ", ";
var query = string.Format("UPDATE {0} SET {1} WHERE {2}", table, valueStr, pkey);
try
{
using (var cmd = destConn.CreateCommand())
{
cmd.CommandText = query;
for (int i = 0; i < srcRow.Count; i++)
{
cmd.Parameters.AddWithValue("?prm" + i.ToString(),srcRow.Values.ElementAt(i));
}
cmd.ExecuteNonQuery();
}
}
Thanks
Shimshon
Try replacing \r\n with \\r\\n,
MySQL receive it and it will escape to database.
I am in the process of fixing some of our bad sql queries that are vulnerable to sql injection. Most are straight queries with no inputs, but our search field takes search terms that are not parameterised. A snippet is below:
using (var db = ORMLite.Open())
{
StringBuilder sb = new StringBuilder();
sb.Append("select * from column1, column2");
if (terms.Count() > 0)
{
sb.Append("where (column1 like '%#term0%' or " + column2 + " like '%#term0%') ");
if (terms.Count() > 1)
{
for (int i = 1; i < terms.Count(); i++)
{
sb.Append("and (column1 like '%#term" + i + "%' or " + column2 + " like '%#term" + i + "%') ");
}
}
}
List<POCO> testQuery = db.Select<POCO>(sb.ToString());
}
The #term components are where I intend to use parameters (they used to be of the form '" + term[i] + '", but any term with malicious code would just be inserted. When I move to my select statement, I would like to add the parameters. This is normally done as so:
List testQuery = db.Select(sb.ToString(), new { term0 = "t", term1 = "te", term2 = "ter" });
However I can have any number of terms (term.count() is the number of terms). How can I pass in an anonymous object with any number of terms? Or is there a better method?
I'm looking for almost the same thing in Postgresql. Based on this SO question
the answer looks like "you have to perform multiple queries."
I can get the unique row IDs from my table given the partial parameterized
query, and then directly paste those unique IDs back into the query -- since those
row IDs will be safe.
Here's an example of what I mean, but the c# is probably wrong (sorry):
string query = "SELECT unique_id FROM table WHERE (column1 LIKE '%#term%' OR column2 LIKE '%#term%')";
string safeIDs;
List uniqueRowIDs = db.Select(query, new {term = term[0]});
for (int i = 1; i < terms.Count(); i++) {
// Loop to narrow down the rows by adding the additional conditions.
safeIDs = uniqueRowIDs.Aggregate( (current, next) => current + string.Format(", '{0}'", next) );
uniqueRowIDs = db.Select(
query + string.Format(" AND unique_id IN ({0})", safeIDs),
new {term = term[i]});
}
// And finally make the last query for the chosen rows:
safeIDs = uniqueRowIDs.Aggregate( (current, next) => current + string.Format(", '{0}'", next) );
List testQuery = db.Select(string.Format("SELECT * FROM table WHERE unique_id IN ({0});", safeIDs));
Another option for your case specifically could be to just get all of the values that
are like term0 using a parameterized query and then, within the c# program, compare
all of the results against the remaining terms the user entered.
I am trying to perform
ALTER TABLE
command in my app, but when running, I am getting this error
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'VARCHAR(10) NOT NULL' at line 1
Here is my code:
for (int k = 0; k < dlzkaTab; k++)
{
string query1 = "ALTER TABLE reflextime ADD " + atributes[k] + " VARCHAR(10) NOT NULL";
MySqlCommand cmd = new MySqlCommand(query1, conect);
cmd.ExecuteScalar();
}
Can anyone please help me?
EDIT:
Here is full code. In the firs for loop I am reading first row from xls file and I am putting it into array atributes. As you can see, I was trying to print out every loaded cell. It worked well (It was printing correct values). However after this for loop the array is printing nothing (empty messagebox).
for (int j = 2; j < colCount; j++)
{
string atr = xlRange.Cells[1, j].Text;
atributes[j]=atr;
MessageBox.Show(atributes[j]);
}
MessageBox.Show("Súbor načítaný");
int dlzkaTab = atributes.Length;
MessageBox.Show(atributes[1]); //empty messagebox
for (int k = 0; k < dlzkaTab; k++)
{
string query1 = "ALTER TABLE reflextime ADD COLUMN " + atributes[k] + " VARCHAR(10) NOT NULL";
MySqlCommand cmd = new MySqlCommand(query1, conect);
cmd.ExecuteScalar();
}
I think you are trying to add a column to the table.
You missed COLUMN keyword in the statement before column name that is being added.
"ALTER TABLE reflextime ADD COLUMN " + atributes[k] + " VARCHAR(10) NOT NULL"
You need to use ExecuteNonQuery instead of ExecuteScalar
And also check your each atributes[k] fro value exist or not
Try this
for (int k = 0; k < dlzkaTab; k++)
{
string query1 = "ALTER TABLE reflextime ADD " + atributes[k] + " VARCHAR(10) NOT NULL";
MySqlCommand cmd = new MySqlCommand(query1, conect);
cmd.ExecuteNonQuery();
}
Can I add a new record into access database which has 15 columns? It's very unconvinient for me to using this sql:
insert into Account(col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12,col13,col14,col15) Values(val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14,val15)
There are 2 List consist columns name (name) and values (info). Example:
name[1]="col1";
info[1]="val1";
Is the ordinary of columns name important? Can I use this Sql:
insert into Account(col1) Values(val1)
After that I use an "update" sql and a "for-loop" to set values?
I also get an error:
The changes you requested to the table were not successful because they would create duplicate values in the index, primary key, or relationship. Change the data in the field or fields that contain duplicate data, remove the index, or redefine the index to permit duplicate entries and try again.
Thank you so much. :)
Do one insert before for loop and update in the for loop.
A sample code is given below.
string Query = "insert into Account(col1) Values(val1)";
// execute it
for(int i=1;i<name.count -1;i++)
{
Query = "Update Account set " + name[i] + " = " + info[i] + " where col1 = val1";
// execute
}
Code not tested.
public static void insert(String[] name ,String[] info)
{
String Names = "";
String Cols = "";
for(int i=0;i < name.Length;i++)
{
Names += (Names == "" ? "" : ", ") + name[i];
Cols += (Cols == "" ? "" : ", ") + "'" + info[i] + "'";
}
String Query = "insert into Account (" + Names + ") Values (" + Cols + ")";
Console.WriteLine(Query);
}
Code not tested and note that I added single quotes for values assuming that all values are string type.