Issue with sql where clause when using datetime - c#

Can anyone help me out with this query i m trying to execute,
static public DataTable GetAllCustomers()
{
string sql = "Select * from [project] where [condition] = 0 AND [Time] < '" + DateTime.Now + "'";
SqlDataAdapter da = new SqlDataAdapter(sql, ConnectionString);
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
It returns nothing
Any ideas where i am getting the query wrong.

Putting DateTime's into SQL Strings is a recipe for disaster thanks to formatting and locations. Change your sql line to:
string sql = "Select * from [project] where [condition] = 0 AND [Time] < GetDate()";
This will use the servers own current date time in whatever format it is expecting.
If you absolutely need to do things client side then use SqlCommand and instead of adding DateTime as a string put a "Time < #" and then add the DateTime as a command parameter. That will avoid formatting problems at least.

Did you know SQL server has a built in time function. Try this:
string sql = "Select * from [project] where [condition] = 0 AND [Time] < GETDATE()";
or if you want date in UTC do this:
string sql = "Select * from [project] where [condition] = 0 AND [Time] < GETUTCDATE()";
This way you do not have any string concatinations in code.
Could you answer the following:
Which part is coming back nothing?
Is [Time] a DATETIME data type or similar (ie: not text)

Related

C# Generate Query to Compare DateTime with SQL Nvarchar date Column

I tried to get result depending on two dates which the user checked.
I have two datetimepicker controls.
I want the user to chooses the "from" date and "to" date,
then the query get specific result.
leaving_time column type is nvarchar
This is my query:
SELECT name, mil_no, rotba, arrival_time, leaving_time, day, year
FROM dbo.Hodor_data
WHERE leaving_time BETWEEN '"+dateTimePicker1.Checked.ToString()+ "' AND '" + dateTimePicker2.Checked.ToString() + '"
Where is the mistake?
You should write parameterized queries and not using string concatenation for passing the parameters, in order to create a sql command. Using string concatenation makes you code vulnerable to sql injections.
var cmdText = #"SELECT ...
FROM dbo.Hodor_data
WHERE leaving_time BETWEEN #StartDate AND #EndDate";
var sqlCommand = new SqlCommand(cmdText, connection);
sqlCommand.Parameters.AddWithValue("#StartDate", dateTimePicker1.Value);
sqlCommand.Parameters.AddWithValue("#EndDate", dateTimePicker2.Value);
where connection is your sql connection object.
Try to use dateTimePicker1.Text in dateTimePicker1_ValueChanged event where you are using dateTimePicker2.Checked that return true or false not the value of date
Checked is a boolean property, and it is not the date. You need to use the Value Property. It is better to add parameters and explicitly specify the type so that the date format conflict is solved.
Edit: If column type in SQL server is NVARCHAR and of format MM/dd/yyyy, you need to use ONVERT(DATETIME, leaving_time, 101):
conn.Open();
SqlDataAdapter dataAdapter =
new SqlDataAdapter("SELECT name, mil_no, rotba, arrival_time, leaving_time, day, year "
+ "FROM dbo.Hodor_data where CONVERT(DATETIME, leaving_time, 101) "
+ "BETWEEN #p1 AND #p2", conn);
SqlParameter fromDate = new SqlParameter("#p1", SqlDbType.DateTime2);
fromDate.Value = dateTimePicker1.Value;
SqlParameter toDate = new SqlParameter("#p2", SqlDbType.DateTime2);
toDate.Value = dateTimePicker2.Value;
dataAdapter.SelectCommand.Parameters.Add(fromDate);
dataAdapter.SelectCommand.Parameters.Add(toDate);
DataTable dt = new DataTable();
dataAdapter.Fill(dt);
dataGridView1.DataSource = dt;
conn.Close()
You should really consider changing the type of column leaving_time to be a DateTime column. This will make your life easier in querying. I can't really see any advantage of storing these values as text.

Search datetime in MySQL

I have a MySQL database, there's a table which have column Time's Type is Nvachar(50) and its values is kind like this "05/09/2012 20:53:40:843" *(Month-date-year hour:mins:second:msecond)*
Now I want to query to get a record have Time after "10/05/2012 01:00:30 PM".
I had code in C# to converted it to "05/10/2012 13:00:30" before making a query.
My Query :
SELECT * FROM ABCDFEGH WHERE capTime > '05/10/2012 13:00:30' LIMIT 0, 1
But i got no record. So please tell me how can I can make it return record have time after the time above ???
More Info My C# code :
string tableName = "ABCDFEGH";
string date = "05/10/2012 13:00:30";
var query = "SELECT * FROM " + tableName + " WHERE capTime > '" + date + "' LIMIT 0, 1";
var cmd = new MySqlCommand(query, connection);
MySqlDataReader dataReader = null;
try
{
dataReader = cmd.ExecuteReader();
}
I'm so so so so so so sorry. I made a mistake the query must be
SELECT * FROM ABCDFEGH WHERE capTime > '05/10/2012 13:00:30' LIMIT 0, 1
This query is successful return the record i need :)
But soemhow I have mistyped it into
SELECT * FROM ABCDFEGH WHERE capTime > '05-10-2012 13:00:30' LIMIT 0, 1
Sorry again, topic close. But tks for evveryone tried :)
I recommend using the DATETIME datatype instead of NVARCHAR. Store dates in YYYY-MM-DD HH:MM:SS format, which is the native DATETIME format recognized by MySQL.
Also use date literals in the same format.
Two reasons for this recommendation: First, DATETIME takes only 8 bytes, instead of up to 150 bytes which is the potential size of a multibyte 50 character varchar.
Second, the sort order of DATETIME will be the same as the chronological order. So if you create an index on the Time column, your > comparison can benefit from the index. Your query will be much faster as a result.
Use TIMESTAMPDIFF()
Schema
CREATE TABLE ABCDFEGH (`right` varchar(3), `time` datetime);
INSERT INTO ABCDFEGH (`right`, `time`)
VALUES
('Yes', '2012-10-02 13:00:30'),
('No', '2012-10-15 13:00:30');
SQL Code
SELECT * FROM ABCDFEGH
WHERE TIMESTAMPDIFF(MINUTE, time, '2012-10-05 13:00:30') > 0
LIMIT 0, 1
Explanation
TIMESTAMPDIFF() returns datetime_expr2 – datetime_expr1, where datetime_expr1 and datetime_expr2 are date or datetime expressions. One expression may be a date and the other a datetime; a date value is treated as a datetime having the time part '00:00:00' where necessary. The unit for the result (an integer) is given by the unit argument.
Fiddle: http://www.sqlfiddle.com/#!2/244cc/1 datetime
Fiddle: http://www.sqlfiddle.com/#!2/063b3/1 varchar(50)
PS1: Time may be a reserved word. Please avoid using it. Else use it with backticks (`).
PS2: The format of time is YYYY-MM-DD not the reverse.
First, why did you save the dates as NVARCHAR? If you are still able to change it to DATETIME datatype and all of the records on it, much better.
But if not, you can use STR_TO_DATE.
SELECT *
FROM tableName
WHERE STR_TO_DATE(`capTime`, '%m/%d/%Y %H:%i:%s:%x') >
STR_TO_DATE('05/10/2012 13:00:30', '%c/%d/%Y %H:%i:%s')
See SQLFiddle Demo
SOURCES
STR_TO_DATE
DATE Formats
UPDATE 1
and your query is vulnerable with SQL Injection. To avoid from it
Parameterized your query
code snippet,
string tableName = "ABCDFEGH";
string date = "05/10/2012 13:00:30";
String query = "SELECT * FROM " + tableName + " WHERE STR_TO_DATE(`capTime`, '%m/%d/%Y %H:%i:%s:%x') > STR_TO_DATE(#dateHere, '%c/%d/%Y %H:%i:%s')";
using (MySqlConnection connection = new MySqlConnection("connectionStringHere"))
{
using (MySqlCommand command = new MySqlCommand())
{
command.Connection = connection;
command.CommandType = CommandType.Text;
command.CommandText = query;
command.Parameters.AddwithValue("#dateHere",date)
MySqlDataReader dataReader = null;
try
{
dataReader = cmd.ExecuteReader();
}
catch(MySqlException e)
{
// do something here
// don't suppress the error
}
}
}

Using WHERE clause with csv files ADO.NET / C#

i have a little problem. I'm using a csv file as database and i'm asking it with ADO.NET's OLEDB funcions.
I want to select only rows where column "DATA" is included between two datas, like this:
String conn = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\;
;Extended Properties='text;HDR=Yes;Format=Delimited(;)';";
OleDbConnection cn = new OleDbConnection(conn);
OleDbCommand cmd = new OleDbCommand("SELECT * FROM [mydb]", cn);
OleDbDataAdapter daAd = new OleDbDataAdapter();
daAd.SelectCommand= cmd;
cn.Open();
DataTable dt = new DataTable();
daAd.Fill(dt);
DateTime mydata= Convert.ToDateTime("01/01/1990");
DateTime mydata2= Convert.ToDateTime("01/01/2000");
Nothing wrong until now, but when i change
"SELECT * FROM [mydb]"
With
"SELECT * FROM [mydb] WHERE DATA>= '"+ mydata.Date +"' AND DATA<='"+ mydata2.Date +"'
I have an error saying "Syntax error (missing operator) in query 'WHERE DATA=> mydata AND DATA<= mydata2'.
I really don't know how to solve it.
More info: .CSV file is formatted like this:
DATA;INFO1;INFO2;INFO3
01/01/1990;1;2;3`
And into schema.ini is this :
[mydb.csv]
Format=Delimited(;)
ColNameHeader=True
DateTimeFormat=dd-MM-yyyy
Col1=DATA DateTime
Col2=info1 Long Width 3
Col3=info2 Integer
Col4=info3 Integer
EDIT :
I'm running a x86 Seven, i read that for solve JET driver's incompatibility is sufficient the schema.ini file, hope i'm right.
Well, this:
SELECT * FROM [mydb] WHERE DATA=> mydata AND DATA<= mydata2
is clearly invalid SQL. Perhaps you meant:
SELECT * FROM [mydb] WHERE DATA>= mydata AND DATA<= mydata2
(You used => for "greater than" rather than >=.)
I think you mean this:
SELECT * FROM [mydb] WHERE DATA >= mydata AND DATA <= mydata2
You just got the => the wrong way round!
UPDATE AFTER OP's CORRECTION
Is it due to your schema.ini? You seem to have the wrong DateTimeFormat:
DateTimeFormat=dd-MM-yyyy
Shouldn't it be:
DateTimeFormat=dd/MM/yyyy
SECOND UPDATE
Change you mydata to the following:
"SELECT * FROM [mydb] WHERE DATA >= '" +
mydata.ToString("dd/MM/yyyy") +
"' AND DATA <= '" + mydata2.ToString("dd/MM/yyyy") + "'"
Try
SELECT * FROM [mydb] WHERE DATA >= mydata AND DATA <= mydata2
Note the order of "<" and "=" in the first comparison.
Because of i'm quering a csv I can't use sql's functions(errors says they don't exist) not even compare my DATA with string. If i put in the query an unquoted date it works, but i don't respect the WHERE clause, selecting all records.
Query seems to doesn't work only for DateTime format, so i'll put my DATA in a yyyyMMdd Integer format.It's the only alternative I've in mind, still don't know why can't search with Datetime fields.

Transact SQL date query returning no results

From my code, I call an SP using:
using (var cmd = new SqlCommand("sp_getnotes"))
{
cmd.Parameters.Add("#ndate", SqlDbType.SmallDateTime).Value
= Convert.ToDateTime(txtChosenDate.Text);
cmd.CommandType = commandType;
cmd.Connection = conn;
var dSet = new DataSet();
using (var adapter = new SqlDataAdapter { SelectCommand = cmd })
{
adapter.Fill(dSet, "ntable");
}
}
The Stored Procedure itself runs a simple query:
SELECT * FROM tblNotes WHERE DateAdded = #ndate
The problem is no records are returned! DateAdded is a smalldatetime column.
When I change the query to the following, it works:
SELECT * FROM tblNotes WHERE CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, DateAdded))) = #ndate
Why is this happening? This change affects the entire application and I'd like to find the root cause before getting into changing every single query... The only changes we made are to use parameterized queries and upgrade from SQL Server 2005 to 2008.
TIA.
smalldatetime has a time portion which needs to match as well.
Use this:
SELECT *
FROM tblNotes
WHERE dateAdded >= CAST(#ndate AS DATE)
AND dateAdded < DATEADD(day, 1, CAST(#ndate AS DATE))
SQL Server 2008 and above also let you use this:
SELECT *
FROM tblNotes
WHERE CAST(dateAdded AS DATE) = CAST(#ndate AS DATE)
efficiently, with the transformation to a range performed by the optimizer.
SQL Server 2008 now has a DATE data type, which doesn't keep the time porttion like SMALLDATETIME does. If you can't change the data type of the column, then you'll have to truncate when doing the compare, or simply cast to DATE:
SELECT *
FROM tblNotes
WHERE cast(dateAdded as date) = #ndate
I don't know SQL Server but from Oracle experience I'd suspect you're comparing a date time with a date, eg 01/01/2012 01:01:01 against 01/01/2012.

In C#, is "SELECT TOP 0 * FROM (/* ... */) s" used in conjuction with ADO.NET a good way to determine the column information in a SELECT statement?

I have a SQL SELECT statement which will not be known until runtime, which could contain JOIN's and inner selects. I need to determine the names and data types of each of the columns of the returned result of the statment from within C#. I am inclined to do something like:
string orginalSelectStatement = "SELECT * FROM MyTable";
string selectStatement = string.Format("SELECT TOP 0 * FROM ({0}) s", orginalSelectStatement);
SqlConnection connection = new SqlConnection(#"MyConnectionString");
SqlDataAdapter adapter = new SqlDataAdapter(selectStatement, connection);
DataTable table = new DataTable();
adapter.Fill(table);
foreach (DataColumn column in table.Columns)
{
Console.WriteLine("Name: {0}; Type: {1}", column.ColumnName, column.DataType);
}
Is there a better way to do what I am trying to do? By "better" I mean either a less resource-intensive way of accomplishing the same task or a more sure way of accomplishing the same task (i.e. for all I know the code snippet I just gave will fail in some situations).
SOLUTION:
First of all, my TOP 0 hack is bad, namely for something like this:
SELECT TOP 0 * FROM (SELECT 0 AS A, 1 AS A) S
In other words, in a sub-select, if two things are aliased to the same name, that throws an error. So it is out of the picture. However, for completeness sake, I went ahead and tested it, along with the two proposed solutions: SET FMTONLY ON and GetSchemaTable.
Here are the results (in milliseconds for 1,000 queries, each):
Schema Time: 3130
TOP 0 Time: 2808
FMTONLY ON Time: 2937
My recommendation would be GetSchemaTable since it's more likely to be future-proofed by a removal of the SET FMTONLY ON as valid SQL and it solves the aliasing problem, even though it is slightly slower. However, if you "know" that duplicate column names will never be an issue, then TOP 0 is faster than GetSchemaTable and is more future-proofed than SET FMTONLY ON.
Here is my experimental code:
int schemaTime = 0;
int topTime = 0;
int fmtOnTime = 0;
SqlConnection connection = new SqlConnection(#"MyConnectionString");
connection.Open();
SqlCommand schemaCommand = new SqlCommand("SELECT * FROM MyTable", connection);
SqlCommand topCommand = new SqlCommand("SELECT TOP 0 * FROM (SELECT * FROM MyTable) S", connection);
SqlCommand fmtOnCommand = new SqlCommand("SET FMTONLY ON; SELECT * FROM MyTable", connection);
for (int i = 0; i < 1000; i++)
{
{
DateTime start = DateTime.Now;
using (SqlDataReader reader = schemaCommand.ExecuteReader(CommandBehavior.SchemaOnly))
{
DataTable table = reader.GetSchemaTable();
}
DateTime stop = DateTime.Now;
TimeSpan span = stop - start;
schemaTime += span.Milliseconds;
}
{
DateTime start = DateTime.Now;
DataTable table = new DataTable();
SqlDataAdapter adapter = new SqlDataAdapter(topCommand);
adapter.Fill(table);
DateTime stop = DateTime.Now;
TimeSpan span = stop - start;
topTime += span.Milliseconds;
}
{
DateTime start = DateTime.Now;
DataTable table = new DataTable();
SqlDataAdapter adapter = new SqlDataAdapter(fmtOnCommand);
adapter.Fill(table);
DateTime stop = DateTime.Now;
TimeSpan span = stop - start;
fmtOnTime += span.Milliseconds;
}
}
Console.WriteLine("Schema Time: " + schemaTime);
Console.WriteLine("TOP 0 Time: " + topTime);
Console.WriteLine("FMTONLY ON Time: " + fmtOnTime);
connection.Close();
You could use GetSchemaTable to do what you want.
There is an example of how to use it here.
If using SQL Server, I would try using SET FMTONLY ON
Returns only metadata to the client. Can be used to test the format of
the response without actually running the query.
Apparently on SQL Server 2012, there's a better way. All is specified in the linked MSDN article.
BTW, this technique is what LINQ To SQL uses internally to determine the result set returned by a stored procedure, etc.
Dynamic SQL is always a bit of a minefield, but you could the SET FMTONLY ON on your query - this means the query will only return Metadata, the same as if no results were returned. So:
string selectStatement = string.Format("SET FMTONLY ON; {0}", orginalSelectStatement);
Alternatively, if you aren't tied to ADO, could you not go down the Linq-to-SQL route and generate a data context which will map out all of your database schemas in to code and their relevant types? You could also have a look at some of the Micro ORMs out there, such as Dapper.Net
There are plenty of other ORMs out there too.

Categories