Insert a new record in access using oledb - c#

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.

Related

How to create a temporary table in MySql from C# datatable?

I am working on a project in which i get some data from a remote server and stores in datatable using C#
DataTable source_db_table;
public void fetch_from_source_db_table(bool verbose, string machine, string table_name, string time_from, string time_to)
{
string query =$"SELECT {table_name}.* " +
$"FROM {table_name} " +
$"WHERE {table_name}" +
$".u_time >='{time_from}' " +
$"AND u_time <= '{time_to}' " +
$"AND mac_id = '{machine}' OR mac_id = 0;";
source_db_table = select_db2(verbose, query);
now I want to use that "datatable" to create a temporary table in MySql . I have searched alot on internet but didnt find anything.
You can do something like this.
StringBuilder sCommand = new StringBuilder("create temporary table tablename(");
foreach (var Col in source_db_table .Columns)
{
sCommand.Append("`"+Col+"`" + " varchar(200), ");
}
sCommand.Append(");");
string scmd = ReplaceLastOccurrence(sCommand.ToString(), ",", "");
in this way your temporary table would be created and now you will just insert rows into this.

Must declare a scalar variable (C# and OleDb)

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.

Use a database value to call a variable with the same name

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.

SQL find rows with key specified in list, C#

I want to make a sql query in C# that finds all rows with a key that is specified in a list. Can I do this with one query? I suppose that is much more efficent than my solution which finds one item at the time inside a for loop, se below:
foreach (int i in list)
{
string Q = "... where pk = " + i.ToString();
using (SqlCommand CM = new SqlCommand(Q, C))
{
using (SqlDataReader R = CM.ExecuteReader())
{
while (R.Read())
{
...
}
}
}
}
list contains different in values.
Thanks in advance!
Replace
string Q = "... where pk = " + i.ToString();
with
string Q = "... where pk IN ('" + string.Join("','", list)+"')";
then you can remove the loop. The result should look like ... where pk IN ('1','2','3')
You can use the IN keyword and pass your list by converting it to a comma seperated string in your query.
Something like
string Q = "select * from tablename where pk IN " + (comma seperated list here);

Using an arbitrary number of parameters in ORMLite Query

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.

Categories