Query from C# code outputting differently from SQL Server query - c#

Working with:
ASP.Net web-forms application
C# code not vb.net
SQL Server with hard coded test data
Note: this issue doesn't cause any errors or cause any disruption in the code, however it outputs differently from expected.
What I am trying to do is populate a Gridview using code behind file, which can be updated by the user on button click.
Code to populate:
protected void PopulateReport()
{
// create connection and add commands
SqlConnection con = new SqlConnection(GetConnectionString());
con.Open();
if(RP_SelectEmp.Text == "ALL")
{
string query1 = "SELECT RequestID, empName, RequestType, RequestDesc, RequestStartDate FROM TOR WHERE (RequestStartDate > #StartDate)" +
" AND (RequestEndDate < #EndDate) AND (granted = #State)";
SqlCommand cmd = new SqlCommand(query1, con);
// needed conversions
DateTime startD = Convert.ToDateTime(RP_FromDateSelect.Text);
DateTime endD = Convert.ToDateTime(RP_EndDateSelect.Text);
Boolean state = Convert.ToBoolean("True");
// needed parameters
cmd.Parameters.AddWithValue("#State", state);
cmd.Parameters.AddWithValue("#StartDate", startD);
cmd.Parameters.AddWithValue("#EndDate", endD);
// import into gridview
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
GridView1.DataSource = reader;
GridView1.DataBind();
}
else
{
RP_ErroField.Text = "failed to bind data (reader not read) check C# code";
}
}
con.Close();
}
}
This compiles and returns no errors but outputs:
The database table includes all the correct data types and column names:
What I have tried:
creating a static data Source and passing in the same select string from the above code (this returns the hard coded event, with the same exact input from the fields seen in the picture) - which tells me the query isn't wrong AddingDataSource,InputingData,Correct event Grabbed
I have tried changing the conversions in the code, DateTime.Parse and Convert.ToDateTime had the same result. Same can be said for bool and Boolean
I have tried the each where clause separately and got the same no data to display result.
I have debugged this if statement for 2 hrs and all the variable data is doing exactly what it should (going to the if, converting, setting the values, running the reader, and databinding)
I don't know what else to try. I would like help on an action plan to fix this; maybe I am missing something, or my approach is wrong/outdated.

This is really just a debugging exercise.
First, double-check that you haven't simply named the two date-picker controls backwards! That happens a lot.
Next: go to SSMS, and take your existing query:
SELECT RequestID, empName, RequestType, RequestDesc, RequestStartDate
FROM TOR
WHERE (RequestStartDate > #StartDate)
AND (RequestEndDate < #EndDate) AND (granted = #State)
Now; we know that you've used Convert.ToDateTime to parse the dates, and that's great. You might want to check the cultures that it is parsing to what you expect it to parse to (is 1/2/2018 the first of Feb? or the 2nd of Jan?), and when you're 100% sure what the actual date of startD and endD are, prepend these to your query using an unambiguous format (just to help us debug); do the same thing with state; for example:
DECLARE #StartDate datetime = '01 Jan 2018';
DECLARE #EndDate datetime = '03 Jan 2018';
DECLARE #State bit = 1;
or are they?
DECLARE #StartDate datetime = '01 Jan 2018';
DECLARE #EndDate datetime = '01 March 2018';
DECLARE #State bit = 1;
So now we have spoofed the parameters and you have the exact same query: run it. 99% of the time, doing this will show you what is wrong with the query. I would expect that the query in SSMS now behaves like the query from your application does. So; now go fix it!

Related

Troubleshooting "Data type mismatch in criteria expression." during MS Access Insert.Into

I'm creating a basic customer inventory application, and when converting the code from using SQL Server to using MS Access (which I'm quite a bit less versed in), I ran into a "Data type mismatch" error when trying to do a basic insert.
I've looked into several similar questions here, and double checked the msdn syntax guide, but I can't find a reason why the script I've written would generate that error. I changed my code several times to try and ensure proper data type (ending up with what I have below with explicit typing and adding the value later). I've actually even taken the string and pasted it into MS Access (sans white space and double quotes), and it seems to work just fine with the values given. At this point, I'm really and truly stumped, and I'm wondering if it might just be a quirk with the Oledb adapter? Any help would be appreciated. Thanks.
// SQL query defined elsewhere:
public static readonly string sqlAddCustomerNotes = "INSERT INTO CustomerNotes (Customer_ID, Notes, NotesDate) "
+ "VALUES(#Customer_ID, #Notes, #NotesDate);";
// end sql query
// data access function
public static void addNotes(int customerID, string notes, DateTime notesDate)
{
string query = Scripts.sqlAddCustomerNotes;
using (
OleDbCommand dbCommand = new OleDbCommand()
{
Connection = new OleDbConnection(ConnectionAccess.connString),
CommandType = CommandType.Text,
CommandText = query,
Parameters =
{
new OleDbParameter("#Customer_ID", OleDbType.Integer),
new OleDbParameter("#Notes", OleDbType.LongVarChar),
new OleDbParameter("#NotesDate", OleDbType.DBTimeStamp)
}
}) // end using parenthetical
{ // begin using scope
dbCommand.Parameters[0].Value = customerID;
dbCommand.Parameters[1].Value = notes;
dbCommand.Parameters[2].Value = notesDate;
foreach (OleDbParameter param in dbCommand.Parameters)
{ // replace ambiguous null values with explicit DBNulls.
if (param.Value == null)
{
param.Value = DBNull.Value;
}
}
dbCommand.Connection.Open();
int rowsAffected = dbCommand.ExecuteNonQuery();
dbCommand.Connection.Close();
Console.WriteLine($"Rows affected: {rowsAffected}");
}
} // end addCustomerNotes
/*
table "CustomerNotes" has the following columns:datatypes
CustomerNotes_ID: AutoNumber
Customer_ID: Number
Notes: Memo
NotesDate: Date/Time
CreateDate: Date/Time
test case (in code) was:
#Customer_ID = 5
#Notes = "customer might change last name to simpson."
#NotesDate = {6/26/2019 12:05:39 PM}
*/
It probably is a date, not a timestamp:
new OleDbParameter("#NotesDate", OleDbType.DBDate)
Considering June7's comment about delimiters, it seems the issue lies in some issue inherent to the OleDbParameter type. In SQL Server terms, I do want DateTime (not Date), but representing it as a DBTimeStamp seems to make it unrecognizable by Access.
For the time being, I've sent the date as a VarChar and allowed Access to convert it however its internal engine sees fit. It feels/seems wrong, but it does, in fact, solve the problem.
Parameters =
{
new OleDbParameter("#Customer_ID", OleDbType.Integer),
new OleDbParameter("#Notes", OleDbType.LongVarChar),
new OleDbParameter("#NotesDate", OleDbType.VarChar)
}
EDIT: Just saw June7's latest comment, and there was in fact, an answer in another thread. OleDbType.DBDate doesn't do what I want, but OleDbType.Date does.

How do I write an SQL query in c# to find DateTime?

So I am creating a search function within my windows form that will allow the user to search for records based on what they have entered into the textbox. I have working code for finding records based off of every filter but the DateTime one. for example:
if (customerID_rb.Checked == true)
{
sqlQuery = "SELECT CustomerID, CustomerName, Telephone, DateAndTime, Status, Description from Calls WHERE CustomerID = " + item;
//'item' is the text in the textbox
UsingCommand(conn, table, sqlQuery);
return table;
}
private static void UsingCommand(SqlConnection conn, DataTable table, string sqlQuery)
{
using (SqlCommand cmd = new SqlCommand(sqlQuery, conn))
{
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
da.Fill(table);
}
}
This will show the records containing the user entered text in the CustomerID column.
However I cannot quite figure out how to do the same but for DateTime. I know that in SQL you type 'WHERE 'DateTime = ...' but no matter how I try to reword the query string I just cannot get it to work.
The error I am getting is : 'SqlException was unhandled: An expression of non-boolean type specified in a context where a condition is expected, near 'DateAndTime'.
Code:
sqlQuery = "SELECT CustomerID, CustomerName, Telephone, DateAndTime, Status, Description from Calls WHERE DateTime DateAndTime = '" + item +"'";
I have tried with and without the DateTime and in multiple different orders, if anyone can help me with this it would be greatly appreciated!
Thanks
Edit:
Ok... I messed up a little. I wrongly assumed you would need the DateTime. However, I may have been thrown off into thinking that because I get thrown an exception if I input the date and time wrong. Thanks! :)
You should never concatenate parameters into a SQL string.
It leaves you vulnerable to SQL injection attacks.
It creates performance problems, as each unique value will create a new SQL query, having a different hash for the query, which defeats the execution-plan caching mechanism of the query engine.
For date values, the ordering of y/m/d, d/m/y, or m/d/y string formats can be different depending on the current culture settings, the OS globalization settings, and the database server's globalization settings. If they're not all in sync, then you could end up with random weirdness like mistaking January 3rd for March 1st.
Instead, you should always parameterize your queries! The query gets a placeholder for the value, and then you add the value using a separate parameter. I'm not going to give you an example here, as it takes very little time to search for this on your own and there have already been hundreds of posts on this here on S.O.
You don't need to specipy the datatype DateTime, Just write the query with column name only like
sqlQuery = "SELECT CustomerID, CustomerName, Telephone, DateAndTime, Status, Description from Calls WHERE columnname = '" + item +"'";
Generally speaking, best would be to add sql parameters, but in string format:
" ... WHERE DateAndTime = '" + item.ToString("yyyyMMdd") +"'"
The yyyyMMdd should be safe to use in all cultures.
The above is assuming, you have to search a date, not including time. Mostly times are only searched on with greater or smaller than.
Additional, if the date field itself contains time, and you only want to search the date:
".... WHERE cast(DateAndTime as date) = '" + item.ToString("yyyyMMdd") +"'"

How to improve stored procedure execution performance?

My task is to call a stored procedure from the Oracle database.
The stored procedure is defined as follows:
CREATE OR REPLACE PROCEDURE my_st_proc
(pname IN VARCHAR2, pdate IN date, o_rc OUT sys_refcursor, o_flag OUT number);
So it takes two input arguments and returns two output arguments, one of which is a cursor.
When testing performance in pl\sql developer with the following code, it completes within 2 - 3 seconds.
DECLARE
pname varchar2(300) := 'john doe';
pdate date := to_date('01/01/1900','dd/mm/yyyy');
o_flag number;
o_data sys_refcursor;
--MyRec describes the fields, returned by the cursor
TYPE MyRec IS RECORD
(cAccount VARCHAR2(20), cBalance number, cDate date, cCurr varchar2(8));
rec MyRec;
BEGIN
my_st_proc(pname,pdate,o_data,o_flag);
dbms_output.put_line(o_flag);
LOOP
FETCH o_data INTO rec;
EXIT WHEN o_data%NOTFOUND;
dbms_output.put_line(
rec.cAccount||','||rec.cBalance||','||rec.cDate||','||rec.cCurr);
END LOOP;
close o_data;
END;
However when I call the stored procedure via ODP.Net it takes up to two seconds more to complete (3 - 5 seconds).
const string p_name = "pname";
const string p_date = "pdate";
const string p_data = "o_data";
const string p_flag = "o_flag";
using (var connection = new OracleConnection("my connection"))
{
var command = connection.CreateCommand();
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "my_st_proc";
var pname = command.Parameters.Add(p_name, OracleDbType.Varchar2);
pname.Direction = ParameterDirection.Input;
var pdate = command.Parameters.Add(p_date, OracleDbType.Date);
pdate.Direction = ParameterDirection.Input;
command.Parameters.Add(p_data, OracleDbType.RefCursor).Direction =
ParameterDirection.Output;
var pflag = command.Parameters.Add(p_flag, OracleDbType.Int32);
pflag.Direction = ParameterDirection.Output;
if (command.Connection.State != ConnectionState.Open)
command.Connection.Open();
command.Parameters[p_name].Value = name;
command.Parameters[p_date].Value = date;
DateTime bdate = DateTime.Now;
command.ExecuteNonQuery();
if (((OracleDecimal)command.Parameters[p_flag].Value).ToInt32() == 1)
{
}
else
{
using (var oreader = command.ExecuteReader())
{
if (oreader != null)
{
try
{
while (oreader.Read()){ }
}
finally
{
oreader.Close();
}
}
}
}
MessageBox.Show(DateTime.Now.Subtract(bdate).ToString());
}
The most time consuming lines of code appeared to be
command.ExecuteNonQuery();
and
command.ExecuteReader()
The number of lines returned by the cursor is not more than 10 - 15, few enough and reading them through the reader does take milliseconds; so I suppose it's not the FetchSize or RowSize issue.
Is there anything I can do to improve performance with ODP.Net in this cituation?
First, you function includes opening the database. I guess in your other tool, you already did the connection and just executed the command. Depending on your database security and location, that easily takes 1-10 seconds.
I don't think this will actually gain you seconds, but you never used CommandType.StoredProcedure. Instead you built SQL yourself. Let ODP.Net worry about that. Just pass the correct comand type and the procedures name as text.
Start by making sure the execution plans are actually the same.
Work with your DBAs and ask them to capture an explain plan for both the stand alone run (aqua data studio) and your odp.net call and confirm they are in fact the same. If they are not, then that will probably explain your problem. You can then try adding "enlist=false" to your connection string but better yet have the DBA's update the statistics on the related tables, hopefully fixing the slow plan. See https://stackoverflow.com/a/14712992/852208 for more info.
I have had this same issue and it came down to oracle being less optimistic about the execution plan when a distributed transaction could be involved.
The above answer is from: https://stackoverflow.com/a/15886630/852208. This is essentially a "runs fine from X but not from Y" so it may be a duplicate but we'll see.

Updating DateTime in access through C#. Data mismatch

I have a date and time loaded into a textbox for editing, but I need to store it as a datetime in my access database not a string and cannot remember or find the syntax to parse it in my SQL parameters... here is my code anyway...
string strSql = "UPDATE OCR SET OCR = #OCR, [OCR Title] = #OCRTitle, DeadlineDate = #DeadlineDate;";
using (OleDbConnection newConn = new OleDbConnection(strProvider))
{
using (OleDbCommand dbCmd = new OleDbCommand(strSql, newConn))
{
dbCmd.CommandType = CommandType.Text;
dbCmd.Parameters.AddWithValue("#OCRTitle", textBox6.Text);
dbCmd.Parameters.AddWithValue("#OCR", textBox5.Text);
dbCmd.Parameters.AddWithValue("#DeadlineDate", textBox7.Text);
newConn.Open();
dbCmd.ExecuteNonQuery();
}
}
You're specifying a string as the deadline date value. You should specify a DateTime instead.
You can use DateTime.Parse (or DateTime.ParseExact, or DateTime.TryParseExact) to parse the text representation if you really have to - but it would be better to use a date-based control to start with, rather than having a text representation at all.
(It's not clear what sort of application this is - WinForms, ASP.NET etc - but most GUIs have some sort of date picker these days.)
EDIT: Additionally, you need to change the order in which you add the parameters to the command such that it matches the order in which the parameters are used in the SQL statement. These are effectively positional parameters - the names are ignored. It would probably be clearer to use ? than named parameters in the SQL.

Error when updating date field in sql server using c#

I am trying to insert a date (date only, not datetime) into sql table (the datatype is date).
I am using the '23/07/2013' format which I am getting from jquery datepicker.
When I execute the following sql, I am getting following error.
SQL: UPDATE qmsAuditFindings SET FindDate='23/07/2013' WHERE AuditID=37
Please advise.
Also its worth mentioning that the insert statement with the exact format works just fine. Just the update that does not.
At the surface, this is simply a formatting issue - but "fixing the formatting" is the wrong way to address this; you should parameterize, such that formatting simply does not apply. Dates don't have a "format", as such - they are just numbers. For example, what we should probably execute is:
UPDATE qmsAuditFindings SET FindDate=#findDate WHERE AuditID=#auditId
To do that you get the DateTime value in your .NET code, and do something like:
DateTime findDate = ...
int auditId = ...
using(var cmd = connection.CreateCommand()) {
cmd.CommandText =
"UPDATE qmsAuditFindings SET FindDate=#findDate WHERE AuditID=#auditId";
cmd.Parameters.AddWithValue("findDate", findDate);
cmd.Parameters.AddWithValue("auditId", auditId);
cmd.ExecuteNonQuery();
}
or more simply with a tool like "dapper":
DateTime findDate = ...
int auditId = ...
connection.Execute(
"UPDATE qmsAuditFindings SET FindDate=#findDate WHERE AuditID=#auditId",
new { findDate, auditId });

Categories