Read Data from .dbf File with OdbcConnection - c#

I am using visual studio 2010 on Win 7. I want to read a .dbf file and get the minimum value of a selected column.
Here is what I have:
System.Data.Odbc.OdbcConnection oConn = new System.Data.Odbc.OdbcConnection();
oConn.ConnectionString = #"Driver={Microsoft dBase Driver (*.dbf)};SourceType=DBF;SourceDB=" + ImportDirPath + ";Exclusive=No; Collate=Machine;NULL=NO;DELETED=NO;BACKGROUNDFETCH=NO;";
oConn.Open();
// Update time
string nowTime = DateTime.Now.ToString("HHmmss");
oCmd.CommandText = #"UPDATE " + tableName + " SET HQCJBS = " + nowTime + " WHERE HQZQDM = ?";
oCmd.Parameters.AddWithValue("row2", "000000");
oCmd.ExecuteNonQuery();
string query = "SELECT MIN(" + colName + ") FROM " + tableName + " WHERE HQZQDM <> 000000";
OdbcDataAdapter da = new OdbcDataAdapter(query, oConn);
DataSet ds = new DataSet();
da.Fill(ds);
Suppose colName and tableName are correct. I have two question.
Two Questions:
When the code da.Fill(ds); is hit, I got an error data type mismatch in criteria expression access, What is wrong?
After I get the minimum value from the database, how can I input it into the memory as a double, for example double min = ds.Tables[0];

Your update command should apply TWO parameters... one for the set, another for the where clause. Use the "?" place-holder for each respectively and add the parameters in the same order as they appear in the query.
string nowTime = DateTime.Now.ToString("HHmmss");
oCmd.CommandText = #"UPDATE " + tableName + " SET HQCJBS = ? WHERE HQZQDM = ?";
oCmd.Parameters.AddWithValue("setParm", nowTime );
oCmd.Parameters.AddWithValue("whereParm, "000000");
oCmd.ExecuteNonQuery();
For your select MIN() query, it appears your WHERE criteria column is a string and by having the literal numbers without quotes is applying it as a numeric... Again, stick with "?" parameters
OdbcCommand getMinCmd = new OdbcCommand("", oConn);
getMinCmd.CommandText = "SELECT MIN(" + colName
+ ") FROM " + tableName + " WHERE HQZQDM <> ?";
getMinCmd.Parameters.AddWithValue("whereParm, "000000");
OdbcDataAdapter da = new OdbcDataAdapter(getMinCmd);
DataSet ds = new DataSet();
da.Fill(ds);
Finally, to get the value OUT of the retrieved query into memory, you need to get the row of the table (only 1 record result set, zero-based index) and column-0 too. Since you did not assign a column name, you don't know the column and just go with 0-index...
int lowestValue = (int)ds.Tables[0].Rows[0][0];
Think of the above as the hierarchy...
ds
tables[0]
rows[0]
[column 0]
rows[1] -- but your query would only have one row anyhow
[column 0]
tables[1] -- if your query had multiple queries, this might be available
but at least it shows where the pieces are.
Now, if you change your query slightly to something like
select MIN( colName ) as MyMinValue ...
then your reference would be where you explicitly name the column from the row retrieved
int lowestValue = (int)ds.Tables[0].Rows[0]["MyMinValue"];

Related

Command parameters

How to correct send parameters to oledb query?
MyCode is
cmd.CommandText = "UPDATE #target SET [#columnname] = Replace([#columnname], Chr(10), '');";
cmd.Parameters.Add(new OleDbParameter("#target", OleDbType.VarChar)).Value = tb_tablename.Text.Trim();
cmd.Parameters.Add(new OleDbParameter("#columnname", OleDbType.VarChar)).Value = column.ColumnName;
And it's not working). I need to add in query #target ( table name ) and #columnname ( column name ).
Modified to code with ?
cmd.CommandText = "UPDATE ? SET [?] = Replace([?], Chr(10), '');";
cmd.Parameters.Add(new OleDbParameter("#target", OleDbType.VarChar)).Value = tb_tablename.Text.Trim();
cmd.Parameters.Add(new OleDbParameter("#columnname", OleDbType.VarChar)).Value = column.ColumnName;
cmd.Parameters.Add(new OleDbParameter("#columnname", OleDbType.VarChar)).Value = column.ColumnName;
Got error:
syntax error in update statement
Concatenation style got error
string query = "UPDATE " + tb_tablename.Text.Trim() + " SET [" + column.ColumnName + "] = Replace([" + column.ColumnName + "], Chr(10), '');";
data type mismatch in criteria expression
Full code:
DataTable dt = new DataTable();
using (OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM " + tb_tablename.Text, conn))
{
adapter.Fill(dt);
}
foreach (DataColumn column in dt.Columns)
{
if (column.DataType == typeof(String))
{
if (column.ColumnName != "ID1" && column.ColumnName != "ID" && column.ColumnName != "Geometry" && column.ColumnName != "Geometry_SK")
{
string query = "UPDATE " + tb_tablename.Text.Trim() + " SET [" + column.ColumnName + "] = Replace([" + column.ColumnName + "], Chr(10), '');";
using (OleDbCommand cmd = new OleDbCommand(query, conn))
{
cmd.ExecuteNonQuery();
}
}
}
}
Whats helped: string query = "UPDATE " + tb_tablename.Text.Trim() + " SET " + column.ColumnName + " = Replace(" + column.ColumnName + ", Chr(10), \"\") WHERE " + column.ColumnName + " <> \"\";";
Blank data + reserved column name brokes all. ColumnNames Date,Type,Note brokes all - exclude it from cycle.
You're getting a syntax error because cannot make a SQL identifier (table name, column name etc) a parameter. Only values can be parameterized
Your query would hence have to look like:
cmd.CommandText = "UPDATE "+tb_tablename.Text+" SET ["+...+"] = Replace(["+...+"], Chr(10), '');";
Never concatenate values supplied by the user, into an SQL. Because you're forced in this instance to concat take and column names in you should absolutely make sure that only safe values are provided. Ideally you should take the value provided for the the table name and column name and have a lot of all table and column names (you can query the db for this) and only permit the sql to build if the values provided are in that list
This is a very unusual requirement- almost no one here seeks to parameterize table names etc. If you're trying to write some sort of mini library to make your data access life easier, I would recommend you use one that already exists like Dapper
You indicated in a comment that you're trying to run a replace on all columns in a db with minimal effort. For this you can consider the following:
use the GetSchema method of your DbConnection object to get a list of the tables in the db
loop Over it, concatenate a string sql of the table name into "SELECT * FROM "+tablename+" WHERE 1=0" and run this sql using a DataAdapter to return an empty datatable with all the columns of the target table
loop over the datatable.Columns collection returned from the above select, running your REPLACE sql, subbing the table and column names in via string concat (it's safe and non hackable because you retrieved the list and are not concatting values provided by a user
if you have non string columns (dates,ints) then examine the datatype of the DataColumn and only run th replace if it's a string/varchar or similar
Helpful links:
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/getschema-and-schema-collections
https://sizious.com/2015/05/11/how-to-load-an-access-database-into-a-dataset-object-in-c/ - goes part way- add a where clause to this guy's code so that no rows are returned (you only want the columns)
You cannot substitute table and column names with parameters.
Parameters can only be applied as follows:
UPDATE SomeTable SET SomeColumn = ?
It is best to allow the user to choose the names of tables and columns from Comboboxes/ListBoxes with ready-made values. Something like this:
var table = tablesComboBox.SelectedItem;
var column = columnsComboBox.SelectedItem;
var query = "UPDATE " + table + " SET " + column +
" = Replace(" + column + ", Chr(10), '''');";
Note that you must escape single quote characters.

Using Subquery as Parameter Value [duplicate]

Im trying to perform a parameterized query in SQLite from C#, and the method im using is along the lines of creating a static command with
SQLiteCommand cmd = new SQLiteCommand(
"SELECT [ID]" +
",[email]" +
",[serializedata]" +
",[restrictions]" +
" FROM " + UserTable +
" WHERE #search = #searchparam", SQLConnection);
cmd.Parameters.Add(new SQLiteParameter("#searchparam"));
cmd.Parameters.Add(new SQLiteParameter("#search"));
and calling it like this:
Command.Parameters["#searchparam"].Value = searchdata;
Command.Parameters["#search"].Value = search;
SQLiteDataAdapter slda = new SQLiteDataAdapter(UserSelectUsernameCommand);
DataSet ds = new DataSet();
slda.Fill(ds);
User[] array = new User[ds.Tables[0].Rows.Count];
int index = 0;
foreach (DataRow row in ds.Tables[0].Rows)
{
array[index] = new User(this, row);
index++;
}
return array;
but im getting an error along the line of " '#search' is not a correct column name " or something like that. if i use a constant column name, and only use the data for parameters it works, but i dont want to create 10 different commands for when i need to search by different column names.
What is the issue here?
Generally things like column names (or table names) can not be parameterised - and the fact that there are different indices means that it will have to be a different plan internally. So you will have to use concatenation - but be careful to white-list the known column names to prevent sql injection:
SQLiteCommand cmd = new SQLiteCommand(#"
SELECT [ID],[email],[serializedata],[restrictions]
FROM " + whiteListedUserTable + #"
WHERE [" + whiteListedColumnName + #"] = #searchparam", SQLConnection);
cmd.Parameters.Add(new SQLiteParameter("#searchparam"));
...
Command.Parameters["#searchparam"].Value = searchdata;
You cannot use a query parameter in that fashion -- to indicate a column name. You can only use it to supply values.
Consider something like this instead:
SQLiteCommand cmd = new SQLiteCommand(
"SELECT [ID]" +
",[email]" +
",[serializedata]" +
",[restrictions]" +
" FROM " + UserTable +
" WHERE [" + search + "] = #searchparam", SQLConnection);
cmd.Parameters.Add(new SQLiteParameter("#searchparam"));
If you control all of the input to this function and none if it can be supplied by someone other than you, this should be safe. But if search comes from an untrusted third party, be sure to make the appropriate security checks on the value.

Conversion between Numeric and Double/Decimal in C#

I'm trying to grab elements from a certain column/Listbox which has the type "numeric" and store them in a List in C#.
datTable = new DataTable();
sqlCmd = new SqlCommand(#
"SELECT DISTINCT [" + form1.getColumnName() + "]
FROM [" + form1.getTableName() + "]", connection);
sqlDatAdapter = new SqlDataAdapter(sqlCmd.CommandText, connection);
sqlDatAdapter.Fill(datTable);
form1.columnStorList.DisplayMember = form1.getColumnName();
form1.columnStorList.ValueMember = "Column1";
form1.costStorList.DataSource = datTable;
List<Decimal> columnElements = new List<Decimal>();
foreach (var selectedItem in form1.columnStorList.SelectedItems)
{
DataRow row = (selectedItem as DataRowView).Row;
columnElements.Add(row.Field<decimal>(form1.getColumnName()));
}
Somehow he don't want to convert it. Double doesn't work at all. For example the value '0,000000' gets displayed as '0'. I tried to convert the elements to Double but then I get '0.0'. Decimal should be the closest to Numeric or am I wrong? How to display it correctly?
I want to use a SELECT Statement (SELECT...FROM...WHERE...=0,000000) to search the value in the database when I highlight it in my Listbox. Since he cuts the values off that specific value won't get found in my database.
The SELECT Statement is:
datTable = new DataTable();
fullStatementColumn = Convert.ToString(columnElements[0]);
String selectStatement = "SELECT [" + form1.colBox.Text + "]
FROM [" + form1.tableNameVal.Text + "]
WHERE convert(varchar(120),[" + form1.getColumnName() + "])='"
+ fullStatementColumn + "'";

C# Parameterized Oracle Update fails on ExecuteNonQuery

I am attempting to dynamically update a set of database tables. I have two variables;
table_name & field_name. These are populated by a foreach loop, that loops through a DataTable. Everytime we hit a new row in the DataTable the names change respectively. Within this loop I create a new Oracle Connection and attempt to write an update with the current table_name/field_name. But Oracle keeps giving me an error on my ExcecuteNonQuery command.
Any help is greatly appreciated!!
EDIT: I have reformatted to include parameters, still does not work does anyone have any ideas on what I am doing wrong?
foreach (DataRow fieldtable in setofTables.Tables[0].Rows)
{
//do work
table_name = fieldtable["table_name"].ToString().Trim();
field_name = fieldtable["field_name"].ToString().Trim();
MessageBox.Show(table_name + field_name);
//create parameters
OracleParameter fieldParamater = new OracleParameter("field_name", OracleDbType.Varchar2);
OracleParameter diffParameter = new OracleParameter("mark_diff_oracle", OracleDbType.BinaryFloat);
OracleParameter wellIdParameter = new OracleParameter("id", OracleDbType.Char);
//wellIdParameter.Size = 10;
//create oracle connection and open
OracleConnection OrclCon2 = new OracleConnection("Data Source=" + dbname + "; User Id=" + userid + ";Password=" + password1 + ";");
OrclCon2.Open();
//prepare sql to be passed to oracle
string UpdateOraSQL = "UPDATE " +table_name+ " set :field_name = :field_name - (:mark_diff_oracle) where id = ':id' and :field_name is not null;";
MessageBox.Show(UpdateOraSQL);
//create dommand
OracleCommand UpdateDB = new OracleCommand(UpdateOraSQL, OrclCon2);
UpdateDB.CommandType = CommandType.Text;
//add parameters
UpdateDB.Parameters.Clear();
UpdateDB.Prepare();
UpdateDB.Parameters.Add(fieldParamater).Value = field_name;
UpdateDB.Parameters.Add(diffParameter).Value = mark_diff_oracle;
UpdateDB.Parameters.Add(wellIdParameter).Value = id;
Remove the semicolon from the end of the sql statement. Change the following code
string UpdateOraSQL = "UPDATE " +table_name+ " set :field_name = :field_name - (:mark_diff_oracle) where id = ':id' and :field_name is not null;";
to
string UpdateOraSQL = "UPDATE " +table_name+ " set :field_name = :field_name - (:mark_diff_oracle) where id = ':id' and :field_name is not null";
See the following link for more information
why the semicolon couldn't place in the CommandText of a OracleCommand when C#
If the problem is still not resolved, it might be helpful if you post the entire exception message also.
AFAIK, you cannot use parameters to define the column that you're updating.
AFAIK, you can only use parameters for the values that you'd want to set.
So, you'll have to create the query using string concat:
string sql = "UPDATE " + tableName + " SET " + fieldName + " = :p_Value WHERE id = :p_Id";
OracleCommand UpdateDB = new OracleCommand(sql, OrclCon2);
UpdateDB.Parameters.Add ("p_Value", ... ).Value = "foo";
UpdateDB.Parameters.Add ("p_Id", ...).Value = 4;
Offcourse, you should make sure that the variables you're adding to the string do not contain any harmfull statements. You should do sanity checks on them.
Perhaps, you can even verify if the tableName or the fieldName that has been passed, is a valid / existing tableName/columnname.
In SQL, one does not say COLUMN <> NULL. The proper syntax is COLUMN IS NOT NULL.

How can i select from table where tablename is specified as SqlParameter?

I am trying to perform dynamic sql select where I am selecting from a table using a parameter.
SELECT null FROM #TableName
However I am getting error must declare table variable #TableName. I suspect this is because I am selecting from a table using a variable. I have not needed to do this before.
List<SqlParameter> sqlParams = new List<SqlParameter>()
{
new SqlParameter("TableName", "testtable"),
new SqlParameter("FieldName", "testfield"),
new SqlParameter("Find", "testfind"),
};
string sqlSelect = "SELECT null FROM #TableName
WHERE #FieldName LIKE '%' + #Find + '%' ";
DataTable dtSelect = SqlHelper.ExecuteDataset(sqlConn, CommandType.Text,
sqlSelect, 30, sqlParams.ToArray()).Tables[0];
//30 = timeout
How can I perform the above using dynamic sql? (no stored procedures please)
You cannot use parameters for things like table and column names. For those you could have a whitelist of possible values and then use string concatenation when building the SQL query.
You can't use parameters like that, so you have to build the query as a string. You could do that in SQL, but you can also just create the string in the C# code.
Make sure that the table name and field name are safe and trusted values, and doesn't come directly from an unsafe source like a web request.
string tableName = "testtable";
string fieldName = "testfield";
List<SqlParameter> sqlParams = new List<SqlParameter>() {
new SqlParameter("Find", "testfind"),
};
string sqlSelect =
"SELECT null " +
"FROM " + tableName + " " +
"WHERE " + fieldName + " LIKE '%' + #Find + '%' ";
private DataTable ExecuteDynamic(string TableName,string FieldName, string Find)
{
string sqlSelect = "SELECT * FROM " + TableName +
" WHERE " + FieldName + " LIKE '%'" + Find + "'%' ";
using (connection = new SqlConnection(Strcon))
connection.Open();
{
using (cmd = new SqlCommand(sqlSelect, connection))
{
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = 60;
adpt = new SqlDataAdapter(cmd);
dt = new DataTable();
adpt.Fill(dt);
return (dt);
}
}
}

Categories