SQLite Query returning entire database - c#

First of all, I'm using C#, as well as the C# wrapper for SQLite.
I am attempting to query my SQLite database using the following code, but it continually returns the entire database instead of what is expected. I am extremely new to sql queries, so please look over my query and let me know if you see anything that might be causing the problem.
public DataTable queryDatabase(String column, String filter)
{
string SQL = "SELECT " + column + " FROM SUBCONTRACTOR " + filter;
SQLiteCommand cmd = new SQLiteCommand(SQL);
cmd.Connection = connection;
SQLiteDataAdapter da = new SQLiteDataAdapter(cmd);
DataSet ds = new DataSet();
try
{
da.Fill(ds);
DataTable dt = ds.Tables[0];
return dt;
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
return null;
}
finally
{
cmd.Dispose();
connection.Close();
}
}
And here is the code I'm running to call the above method...
dataGridView.DataSource = sqliteQuery.queryDatabase("*", "WHERE GLOPolicy != 'True' OR ALPolicy != 'True' OR WCPolicy != 'True' OR ULPolicy != 'True' AND BusinessName LIKE '%" + bySubBusinessNameMaskedTextBox.Text + "%' AND Contact LIKE '%" + bySubContactNameMaskedTextBox.Text + "%'");
Thanks for any help, as always!
EDIT:
With my query, I am attempting to select all records that have...
(GLOPolicy != true OR ALPolicy != true OR WCPolicy != True OR ULPolicy != True)
AND
BusinessName LIKE [business name variable here]
AND
ContactName LIKE [contact name variable here]

James is right (in comment).
Because AND has higher precedence than OR, your WHERE clause essentially says:
WHERE
GLOPolicy != 'True' OR ALPolicy != 'True' OR WCPolicy != 'True' OR
(ULPolicy != 'True' AND BusinessName LIKE '%x%' AND Contact LIKE '%y%')
You can fix by adding parens around all ORd conditions to ensure that they are evaluated before getting mixed in with the ANDs:
WHERE
(GLOPolicy != 'True' OR ALPolicy != 'True' OR WCPolicy != 'True' OR
ULPolicy != 'True') AND BusinessName LIKE '%x%' AND Contact LIKE '%y%'
Also: I think that your code is vulnerable to SQL-injection attacks. I am not fluent in C#, but there should be some built-in way to pass parameters to your query.
Edit:
It now seems, in the comments, that there is something else going on here.
I would suggest the following debugging methods:
use the recommended way of passing parameters,
try running the query with just one of the LIKE conditions at a time; verify that results are as you expect,
ensure that the parameters you are passing contain what you expect.
Aside from that: Posting your schema and data—since it's only 3 rows—couldn't hurt.

Related

.NET: How to deal with possible null values in an SQL query?

Code:
private void DoSomethingWithDatabase(string f1, int f2)
{
SqlCommand myCommand = new SqlCommand("SELECT Field1,Field2,Field3 FROM MyTable WHERE Field1 = #F1 AND Field2 = #F2", this.myConn);
myCommand.Parameters.Add("#F1", System.Data.SqlDbType.VarChar);
myCommand.Parameters.Add("#F2", System.Data.SqlDbType.Int);
if (f1 == "")
myCommand.Parameters["#F1"].Value = DBNull.Value;
else
myCommand.Parameters["#F1"].Value = f1;
if (f2 < 0)
myCommand.Parameters["#F2"].Value = DBNull.Value;
else
myCommand.Parameters["#F2"].Value = f2;
// code to do stuff with the results here
}
The server is a Microsoft SQL Server instance.
The database table MyTable contains fields which are nullable. Therefore null is a valid value to search on when performing the query.
From my reading, and also from testing code like this, doing something like what I did here doesn't work properly because apparently you can't do an "equals null" comparison this way - you're supposed to do "IS NULL".
It looks like you can correct this and make it work by setting ANSI_NULL to OFF (as per https://msdn.microsoft.com/en-us/library/ms188048.aspx) but it also indicates this method is deprecated and should not be used.
That article suggests you can use an OR operator to do something like WHERE Field1 = 25 OR Field1 IS NULL. The problem is, with a single call to this function, I want to check for either null and only null, or for the given constant value and nothing else.
So far, it seems like I need to basically build the query piece by piece, string by string, to account for the possibility of NULL values. So I'd need to do something like:
string theQuery = "SELECT Field1,Field2,Field3 FROM MyTable WHERE ";
if (f1 == "")
theQuery += "Field1 IS NULL ";
else
theQuery += "Field1 = #F1 ";
// ...
SqlCommand myCommand = new SqlCommand(theQuery, this.myConn);
if (f1 == "")
{
myCommand.Parameters.Add("#F1", System.Data.SqlDbType.VarChar);
myCommand.Parameters["#F1"].Value = f1;
}
// ...
Is this really how it needs to be done? Is there a more efficient way to do this without repeating that if block and by using parameters rather than concatenating a query string together?
(Notes: An empty string is converted to a NULL here for the example. In the scenario I'm actually working with, empty strings are never used, but instead NULL is stored. The database is out of my control, so I can't just say "change all your NULLs to empty strings". Same goes for the ints - if we pass, say, -1 into the function it should be testing for a null value. Bad practice? Maybe, but the database itself is not in my control, only the code to access it is.)
Why not using:
string theQuery = "SELECT Field1, Field2, Field3 FROM MyTable WHERE ISNULL(Field1,'') = #F1";
?
That way you get rid of your if block and your null values are interpreted as an empty string, like your f1 variable.
SQL Server has a function called ISNULL(Column,Value) where you can specify one column to check and set a Default Value in case this Column is NULL.
You can check here
You could do something like
WHERE ISNULL(Field, '') = #F1
In that case, NULL fields are treated like empty strings. Another way would be:
WHERE Field IS NULL OR Field = #1
The way you are dealing with NULLs is the right way. Maybe you could use a helper method like this one:
private string AppendParameter(string query, string parameterName, string parameterValue, SqlParameterCollection parameters)
{
if (string.IsNullOrEmpty(parameterValue))
query += "Field1 IS NULL ";
else
{
query += "Field1 = " + parameterName + " ";
parameters.AddWithValue(parameterName, parameterValue);
}
return query;
}
SqlCommand myCommand = new SqlCommand(#"SELECT Field1,Field2,Field3
FROM MyTable
WHERE
( (#F1 IS NULL AND [field1] IS NULL) OR [field1] = #F1 ) AND
( (#F2 IS NULL AND [field2] IS NULL) OR [field2] = #F2 );", this.myconn);
myCommand.Parameters.Add("#F1", System.Data.SqlDbType.VarChar).Value = DBNull.Value;
myCommand.Parameters.Add("#F2", System.Data.SqlDbType.Int).Value = DBNull.Value;
if (!string.IsNullOrEmpty(f1))
myCommand.Parameters["#F1"].Value = f1;
if (f2 != -1)
myCommand.Parameters["#F2"].Value = f2;
This would utilize indexes on fields.
If you want to avoid if blocks, you can probably change the query into something like this:
SELECT Field1,Field2,Field3 FROM MyTable
WHERE COALESCE(Field1,'') = #F1 AND COALESCE(Field2,-1) = #F2

Updating a DB (SQL Server) using Ids from a dataTable in C# without For loop

its my first question on S.O, also I'm kinda new in c# and SqlServer.
so pretty please be nice.
I have a dataTable with 4 columns: id1, id2, id3, id4 (and several rows)
also I have a SQL Server DB containing the 4 columns and additional columns, 2 of them named field1 and field2
I want to Update field1 and field2 to null in the db (without using foreach Row)
I've succeeded updating the first row using this:
public void UpdateDt(DataTable dt, string ConnectionString)
{
Conn = null;
DataRow row = dt.Rows[0]
try
{
Conn = new SqlConnection(ConnectionString);
Conn.Open();
string sql = "update [DB].[dbo].[MyTable] set [field1] = null,"+
"[field2] = null where [ID1] = '"+row["ID1"]+"' and [ID2] = '"+row["ID2"]+"' "+
"and [ID3] = '"+row["ID3"]+"' and [ID4] = '"+row["ID4"]+"'";
var sqlDataAdapter = new SqlDataAdapter { UpdateCommand = Conn.CreateCommand() };
sqlDataAdapter.UpdateCommand.CommandText = sql;
sqlDataAdapter.UpdateCommand.BeginExecuteNonQuery();
}
catch( Exception ex) log(ex);
finally
{
if (Conn != null)
{
Conn.Close();
Conn.Dispose();
}
}
}
how can I update using the entire DataTable?
please help
thanks in advance
-- response to comment by Soner Gönül
I've changed the sample code according to your advice, thanks
Zohar,thanks, I've chosen the fields names in order to try and make the question more general and understandable
---edit---
I've added a code for updating the entire DataTable using ForEach (with the help of Russ (thanks Russ))
bool UpdateDt(DataTable dt)
{
Conn = null;
try
{
Conn = new SqlConnection(ConnectionString);
Conn.Open();
string sql = "update [KeywordInjectionData] " +
"set " +
"[field1] = null " +
",[field2] = null " +
"where " +
"[Id1] = #Id1" +
" and [Id2] = #Id2" +
" and [Id3] = #Id3" +
" and [Id4] = #Id4;" ;
var sqlDataAdapter = new SqlDataAdapter { UpdateCommand = Conn.CreateCommand() };
foreach (DataRow row in dt.Rows)
{
sqlDataAdapter.UpdateCommand.CommandText = sql;
sqlDataAdapter.UpdateCommand.Parameters.AddWithValue("#Id1",row["Id1"]);
sqlDataAdapter.UpdateCommand.Parameters.AddWithValue("#Id2",row["Id2"]);
sqlDataAdapter.UpdateCommand.Parameters.AddWithValue("#Id3",row["Id3"]);
sqlDataAdapter.UpdateCommand.Parameters.AddWithValue("#Id4",row["Id4"]);
sqlDataAdapter.UpdateCommand.ExecuteNonQuery();
sqlDataAdapter.UpdateCommand.Parameters.Clear();
}
}
catch (Exception e1)
{
Utillties.LogError(e1);
return false;
}
finally
{
if (Conn != null)
{
Conn.Close();
Conn.Dispose();
}
}
return true;
}
but the question remains, how can I update the DB without a ForEach loop?
First off, the way you are structuring your query is extremely dangerous as it will allow SQL Injections--you should only use parameterized queries (as mentioned by Soner Gonul in the comments above).
Second you can loop through each row with a Foreach clause:
Foreach (DataRow row in dt.Rows)
In doing this, however, you should move the connection declaration and open before the Foreach so that you only open the connection once.
I'm not sure why you wouldn't want to use a loop in this instance. In general, at a pure database level, loops are considered "bad", but that's really an over simplification of the issue... (I've written many queries that are faster with a loop than without)
Let's start by removing C# from the question, and instead make it "how to update all desired rows in a table at once?" Since the new values are all the same, it's possible, provided you can create the appropriate where clause. In this case, since you're attempting to update a random set of rows based on (I assume) user input, it would need to look like the following:
UPDATE dbo.MyTable
SET field1 = null, field2 = null
WHERE (id1 = #m1_id1 AND id2 = #m1_id2 AND id3 = #m1_id3)
OR (id1 = #m2_id1 AND id2 = #m2_id2 AND id3 = #m2_id3)
OR (id1 = #m3_id1 AND id2 = #m3_id2 AND id3 = #m3_id3)
etc.
Which get's silly rather quick. For the sake of completeness, if instead you were referencing another table in the database, it would be possible to do the following (under most RDBMS's):
UPDATE myT
SET field1 = null, field2 = null
FROM dbo.MyTable myT
JOIN dbo.SetsToUpdate s ON myT.id1=s.id1
AND myT.id2=s.id2
AND myT.id3=s.id3
However, you're not starting with another table, and setting one up, populating it and cleaning it up most likely requires more resources than simply multiple single row updates.
So, we're back at a loop, but one that's performed in C# which does loops quite effectively. Further, aside from performance, the only other reason to want a single update statement is data atomicity, which is handled quite nicely with transactions.
If you really do see performance issues at the database level here, the question is one of database optimization (look into indexes). But please, don't fall into the trap of premature optimization.

SqlCommand SUM(NVL()) issue

Hello I'm trying to select SUM of all payments but got this exception: nvl is not a recognized function name
with this code:
SqlCommand sc2 = new SqlCommand("SELECT SUM(NVL(payments,0)) AS sumcastka FROM kliplat WHERE akce=" + zakce.Text, spojeni);
spojeni.Open();
int sumOfPrice = 0;
object vysledek2 = sc2.ExecuteScalar();
if (vysledek2 != DBNull.Value)
sumOfPrice = Convert.ToInt32(vysledek2);
// int vysledek2 = Convert.ToInt32(sc2.ExecuteScalar());
spojeni.Close();
This should work as when no records are found for column "payments" I would like to get "0" if possible.
Thank you for reading this.
NVL() is an oracle-specific function. You can use the ANSI COALSECE function to perform the same task. The benefit of COALESCE is that it takes more than two parameters, and picks the first non-null value.
This should work as when no records are found for column "payments"
No, it will only treat NULL values in the payments column as 0.
If no records are found, then ExecuteScalar returns null (not DBNull):
SqlCommand sc2 = new SqlCommand("SELECT SUM(ISNULL(payments,0)) AS sumcastka FROM kliplat WHERE akce=" + zakce.Text, spojeni);
spojeni.Open();
int sumOfPrice = 0;
object vysledek2 = sc2.ExecuteScalar();
if (vysledek2 != null && vysledek2 != DBNull.Value)
sumOfPrice = Convert.ToInt32(vysledek2);
spojeni.Close();
You should also look into using SqlParameters instead of concatenating strings, but that's a separate issue.
In SQL server there is a funcation called ISNULL for the purpose. Please find the query below:
SELECT SUM(ISNULL(payments,0)) AS sumcastka FROM kliplat WHERE akce=" + zakce.Text, spojeni

DataSet coming as Empty

I have a method called searchDB that search the database according to keyword typed by user.
I am storing the search results in DataSet. This method search in only one column.
public DataSet searchDB(string identifier)
{
DataSet dataSet = new DataSet();
OleDbConnection oleConn = new OleDbConnection(connString);
try
{
oleConn.Open();
string sql = "SELECT [identifier] FROM [Category3] WHERE [identifier] LIKE '" + identifier + "*'";
//string sql = "SELECT [identifier] FROM [Category3]";
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(sql, oleConn);
dataAdapter.Fill(dataSet, "identifier");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
oleConn.Close();
}
if (dataSet.Tables[0].Rows.Count == 0)
{
return null;
}
else
return dataSet;
}
The variable "identifier" gets value from the textbox.
Suppose, when i pass "windows" as value for variable, it should return 1 row.
But when i put breakpoint, it is hitting the if condition
if (dataSet.Tables[0].Rows.Count == 0)
{
return null;
}
and returning 0 rows.
Can anyone point out my mistake.
You seem to be using the SQL LIKE wrong (unless your identifier column really ends with an asterisk):
SELECT [identifier] FROM [Category3] WHERE [identifier] LIKE '" + identifier + "*'
Like uses the % character for wildcard, instead of *, so try:
SELECT [identifier] FROM [Category3] WHERE [identifier] LIKE '" + identifier + "%'
Edit: I didn't see that the question concerns MS Access, but the answer holds true still. See the following SO question: Why does a LIKE query in Access not return any records?
The Access Database Engine (Jet, ACE, whatever) has two ANSI Query Modes which each use different wildcard > characters for LIKE:
ANSI-89 Query Mode uses *
ANSI-92 Query Mode uses %
The LIKE filter should use % instead of * like here:
LIKE '" + identifier + "%'

Issue with conducting SQL statement within ASP.Net C# code

doubles quotes dont work so you have to type 'some value' to actually do variable comparisons when doing direct execution of SQL statements.
Problem is that now when I execute the SQL statement from ASP.NET code I dont seem to be getting any readings...I am not even getting errors :S....
I HAVE tried executing the SQL statement on its own, and it does work.
public static string testExi(string localIncidentNum)
{
try
{
string query = "SELECT TOP 1 UniqueColID From DBNAME WHERE LocalIncidentNum = #localIncidentNum ORDER BY [version] DESC";
DataTable dt = new DataTable();
SqlConnection connection = new SqlConnection(connectionStr);
SqlCommand command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("#localIncidentNum", localIncidentNum);
connection.Open();
SqlDataAdapter adp = new SqlDataAdapter(command);
adp.Fill(dt);
connection.Close();
command.Dispose();
connection.Dispose();
if (dt.Rows.Count != 0)
{
string UniqueColID = dt.Rows[0]["UniqueColID"].ToString();
return UniqueColID;
}
else
{
return null;
}
string some = dt.Rows[0]["UniqueColID"].ToString();
return some;
}
catch (Exception err)
{
Global.tmpmsg = " Updating follow up was not successful. " + err.ToString();
return null;
}
}
If I hardcode an incident value in the SELECT statement it works but if I hardcode the incident value in .addwithvalue, it doesn't work.
command.Parameters.AddWithValue("#localIncidentNum", "12-023696");
Double check your sql statement:
SELECT TOP 1 UniqueColID From WHERE LocalIncidentNum = #localIncidentNum ORDER BY [version] DESC
From Where?
Edit
In observance of your change, best to always be as accurate as possible when describing your problem. Leaving out something like the table name of a sql statement is very misleading.
Perhaps add a datatype to your command parameter. I believe that you are not getting anything because it may be timing out on the command.
command.Parameters.AddWithValue("#localIncidentNum", localIncidentNum);
command.Parameters[0].SqlDbType = SqlDbType.VarChar;
I found a similar problem here, also using Varchar:
AddWithValue without DBType causing queries to run slowly
I solved it. The problem was that I (for some reason) needed to put the full path of the table before the table name in sql code when executing it from C sharp file:
SELECT TOP 2 [DB name].[dbo]. [table name]

Categories

Resources