I need to ask something again. I'm a PHP developer for two years. Previously, I got my hands with Java for a year and C# for at least some couple of months before Java. I'm in the process of relearning C#. The following C# string declaration is from a tested SQL script that determines if a reservation entry (from the [RESERVATION] table) overlaps with an existing Pending reservation (filtered by the [status] as [r] where clause)
string query = "select [r].[id], [first_name], [middle_name], [surname], [extension], [reservation_time_from], [reservation_time_to] " +
"from [RESERVATION] as [r] " +
"join [CUSTOMER] as [c] on [r].[customer_id] = [c].[id] " +
"where [reservation_date] = #reservation_date and " +
"( #reservation_time_from between [reservation_time_from] and [reservation_time_to] or " +
"#reservation_time_to between [reservation_time_from] and [reservation_time_to] " +
") or " +
"( [reservation_time_from] between #reservation_time_from and #reservation_time_to " +
"or [reservation_time_to] between #reservation_time_from and #reservation_time_to " +
") and " +
"[status] = 'Pending' " +
"order by [transaction_date] asc";
I attached the parameters using this method:
command.Parameters.AddWithValue();
Now when I perform the query using the command.ExecuteReader(), it seems that the query does not fetch overlap schedules of [RESERVATION]. I got a hunch that it has something to do with the source of the data: that is a DateTimePicker object; since the column type of the columns are date only, but I'm not quite sure. I attached the values of those time picker using this code (that is a parameter for a time column):
command.Parameters.AddWithValue("#reservation_time_from", SqlDbType.Date).Value = ((DateTime)param[value]).TimeOfDay;
Can someone assist me? Note though that some parameters (such as #reservation_time_from) occurred at least twice on the query string. Thanks for the support.
EDIT:
These is how I attached parameters (sorry the previous example is wrongly pasted, Tee hee):
command.Parameters.AddWithValue("#reservation_time_from", SqlDbType.Time).Value = ((DateTime)param['reservation_time_from']).TimeOfDay;
command.Parameters.AddWithValue("#reservation_time_to", SqlDbType.Time).Value = ((DateTime)param['reservation_time_to']).TimeOfDay;
command.Parameters.AddWithValue("#reservation_date_from", SqlDbType.Date).Value = ((DateTime)param['reservation_date_from']).Date;
command.Parameters.AddWithValue("#reservation_date_to", SqlDbType.Date).Value = ((DateTime)param['reservation_date_to']).Date;
AddWithValue takes the value as the second parameter, and so is interpreting the SqlDbType as the parameter value. You will need to use Add instead of AddWithValue:
command.Parameters.Add("#reservation_time_from", SqlDbType.Time)
.Value = ((DateTime)param[value]).TimeOfDay;
From the documentation:
AddWithValue replaces the SqlParameterCollection.Add method that takes
a String and an Object. The overload of Add that takes a string and an
object was deprecated because of possible ambiguity with the
SqlParameterCollection.Add overload that takes a String and a
SqlDbType enumeration value where passing an integer with the string
could be interpreted as being either the parameter value or the
corresponding SqlDbType value.
Edit: what you're doing only works because the SqlCommand is correctly assigning the SqlDbType based on the value provided in the Value set and the SqlDbType is irrelevant: run this code to see:
var cmd = new SqlCommand();
var param = cmd.Parameters.AddWithValue("#date_from", SqlDbType.Date);
Console.WriteLine(param.ParameterName);
Console.WriteLine(param.SqlDbType);
Console.WriteLine(param.Value.GetType());
Console.WriteLine();
param.Value = DateTime.Today;
Console.WriteLine(param.ParameterName);
Console.WriteLine(param.SqlDbType);
Console.WriteLine(param.Value.GetType());
This outputs:
#date_from
Int
System.Data.SqlDbType
#date_from
DateTime
System.DateTime
Sorry my bad, it seems that I've slightly overlooked the mapping of sql type on some of the parameters:
command.Parameters.AddWithValue("#reservation_date_from", SqlDbType.Date).Value = ((DateTime)param['reservation_date_from']).Date;
command.Parameters.AddWithValue("#reservation_date_to", SqlDbType.Date).Value = ((DateTime)param['reservation_date_to']).Date;
Instead of using SqlDbType.Date, I must use SqlDbType.DateTime. I overlooked that the sql type of the columns [reservation_date_from] and [reservation_date_to] are both DateTime. Now the overlap trap works like a charm. Sorry for the silly mistake...
Related
I am facing a problem on passing the DateTime.Now into Access database:
oleDBCommand.CommandText =
"INSERT INTO tblData "([PIC], [Sampling Date]) "VALUES (#PIC, #SamplingDate)";
oleDBCommand.Parameters.Add(new OleDbParameter("#PIC", combobox1.Text));
oleDBCommand.Parameters.Add(new OleDbParameter("#SamplingDate", DateTime.Now));
I tried a lot of methods from the internet like using oleDBType.Date, DateTime.Now.ToString(), using AddWithValue..... And none of it is working.
Note 1: Database setting [Sampling Date] = Data Type: Date/Time (Format - Long Time), database was
Note 2: Below code was working but I prefer to using .parameters as it look much more organize and easy to manage.
oleDBCommand.CommandText =
"INSERT INTO tblData ([PIC], [Sampling Date]) " VALUES ('" + combobox1.Text + "', '" + DateTime.Now + "')";
You dont need to pass parameter when specifying current date.
Let the ms access sql query handle it, you need to replace #SamplingDate parameter to Date() for example
cmd.CommandText = "INSERT INTO tblData ([PIC], [Sampling Date]) VALUES (#PIC, Date())";
Here is the best explanation Insert today's date
I was struggling with this this week and the accepted answer really did not help me. I found that if I did the assignment of the date+time as an ODBC canonical string (yyyy-mm-dd hh:mi:ss), it worked just fine. So, my C# code looked something like:
InsertCommand.Parameters.Add("#" + column.ColumnName, OleDbType.DBTimeStamp).Value = DateTime.Now.ToString("u");
for the first row and then
InsertCommand.Parameters.Add("#" + column.ColumnName).Value = DateTime.Now.ToString("u")
for the rest.
Try This,
cmd.CommandText = "INSERT INTO tblData ([PIC], [Sampling Date]) VALUES (#PIC, #SamplingDate)";
cmd.Parameters.Add("#PIC",OleDbType.VarChar).Value = combobox1.Text;
cmd.Parameters.Add("#PIC", OleDbType.Date).Value = DateTime.Now;
c# ms-access
My friend wants to transfer her data from the database to a textbox to her program in c# but it gets an error of this:
"Data is Null. This method or property cannot be called on Null
values."
Here is the code by the way:
sql_command = new MySqlCommand("select sum(lt_min_hours) as TotalLate from tbl_late where (late_date between '" + date_start + "' and '" + date_to + "' and empid = '" + empid + "')", sql_connect);
sql_reader = sql_command.ExecuteReader();
if (sql_reader.Read())
{
textBox_tlate.Text = sql_reader.GetString("TotalLate");
}
else
{
MessageBox.Show("No Data.");
}
From documentation;
SUM() returns NULL if there were no matching rows.
But first of all, You should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
After that, you can use ExecuteScalar instead of ExecuteReader which is returns only one column with one row. In your case, this is exactly what you want.
textBox_tlate.Text = sql_command.ExecuteScalar().ToString();
Also use using statement to dispose your connection and command automatically.
You need to test for DbNull.Value against your field before assigning it to the textbox
if (sql_reader.Read())
{
if(!sql_reader.IsDbNull(sql_reader.GetOrdinal("TotalLate")))
textBox_tlate.Text = sql_reader.GetString("TotalLate");
}
EDIT
According to your comment, nothing happens, so the WHERE condition fails to retrieve any record and the result is a NULL.
Looking at your query I suppose that your variables containing dates are converted to a string in an invalid format. This could be fixed using a ToString and a proper format string (IE: yyyy-MM-dd) but the correct way to handle this is through a parameterized query
sql_command = new MySqlCommand(#"select sum(lt_min_hours) as TotalLate
from tbl_late
where (late_date between #init and #end and empid = #id", sql_connect);
sql_command.Parameters.Add("#init", MySqlDbType.Date).Value = date_start;
sql_command.Parameters.Add("#end", MySqlDbType.Date).Value = date_end;
sql_command.Parameters.Add("#id", MySqlDbType.Int32).Value = empid;
sql_reader = sql_command.ExecuteReader();
This assumes that date_start and date_end are DateTime variables and empid is an integer one. In this way, the parsing of the parameters is done by the MySql engine that knows how to handle a DateTime variable. Instead your code uses the automatic conversion made by the Net Framework that, by default, uses your locale settings to convert a date to a string.
Two small issues, mostly concerning the #AT syntax when dealing with data in ASP.Net (C#). Most online tutorials show a lot of this following type of code but fail to mention (or I may have overlooked) the actual purpose of the ampersand although they do explain the general purpose of the code. In this example, just querying the database to get data pertaining to a certain month for a calender control.
protected DataSet GetCurrentMonthData(DateTime firstDate,
DateTime lastDate)
{
DataSet dsMonth = new DataSet();
ConnectionStringSettings cs;
cs = ConfigurationManager.ConnectionStrings["ConnectionString1"];
String connString = cs.ConnectionString;
SqlConnection dbConnection = new SqlConnection(connString);
String query;
query = "SELECT HolidayDate FROM Holidays " + _
" WHERE HolidayDate >= #firstDate AND HolidayDate < #lastDate";
SqlCommand dbCommand = new SqlCommand(query, dbConnection);
dbCommand.Parameters.Add(new SqlParameter("#firstDate",
firstDate));
dbCommand.Parameters.Add(new SqlParameter("#lastDate", lastDate));
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(dbCommand);
try
{
sqlDataAdapter.Fill(dsMonth);
}
catch {}
return dsMonth;
}
First issue: What do #firstDate and #lastDate mean or reference in the database string query? Is that referencing the parameters being passed in GetCurrentMonthData method or the actual column name in the database table ?
query = "SELECT HolidayDate FROM Holidays " + _
" WHERE HolidayDate >= #firstDate AND HolidayDate < #lastDate";
Second issue: What is the difference between #firstDate and firstDate? Am I correct in saying firstDate is the actual parameter variable itself?
dbCommand.Parameters.Add(new SqlParameter("#firstDate",
firstDate));
I agree with #har07. That is not a ampersand. An ampersand, as far as I know, looks like this -> &. To answer the question, the 'at' sign (#) is used to indicate variables in a parameterized query in c#.
In the code
dbCommand.Parameters.Add(new SqlParameter("#firstDate",firstDate));
you are assigning the value of the DateTime variable firstDate to the #firstDate variable in your query.
Here's an example that's a bit less confusing(I hope):
Let's say I have a string variable called myName and I want to pass that to my query select * from students where name = #name.
To pass the value of myName to #name in my query, I would do
dbCommand.Parameters.Add(new SqlParameter("#name",myName));
I hope that helps.
Your First Question :
According to the documentation, the name must start with an #:
The ParameterName is specified in the form #paramname.
More Information :
Is it necessary to add a # in front of an SqlParameter name?
Second Question :
First, that isn't ampersand but at sign or commercial at. It is used in this particular context to indicates an SQL parameter name.
And this part showing how you pass the actual value (contained in the firstDate C# variable) to the SQL parameter (#firstDate) :
dbCommand.Parameters.Add(new SqlParameter("#firstDate",
firstDate));
You can read your parameterized SQL query statement like string concatenation but with big advantages (the former save you from SQL injection, arbitrary data type to string conversion with correct formatting*, etc) :
query = "SELECT HolidayDate FROM Holidays " + _
" WHERE HolidayDate >= " + firstDate + " AND HolidayDate < " + lastDate;
*) See that in the string concatenation version above you need to convert firstDate and lastDate to string with correct format according to your RDBMS local settings to make it work.
The main use of #inputvalue in query statement is to avoid sql injection attacks.
If you use normal concatenation method in building query statement, Hackers can easily bypass the statements with sql injection.
Eg:
"Select * from user where username ='" + username.text + "' and password ='" + password.text + "'"
If you use the above statement to validate the user login, think what will happen if the user types a' = 'a') or 'sometext in username textbox and sometext in password box. It will returns more than one record on execution and enters into account area, if you checks with no of return records in user validation.
To avoid this, Microsoft introduced #parameter to build sql query statements. Whatever value you pass in the #parameter is considered as input parameter value and you can't inject sql statements in it.
Answer for your second question
dbCommand.Parameters.Add(new SqlParameter("#firstDate",
firstDate));
The above method is used to replace the #parameter(first argument in Add method) with parameter value(second argument in Add method). It uses # as the delimiter. it checks if there is a word with prefix '#' in query statement, it will be marked as a parameter and it is replaced by the actual value which is passed as the second argument in the Add method.
I have A anb B in String format
A = 14/01/2007
B = 22:10:39
I try to insert date and time:
SQL = "insert into MyTbl(Tdate,Ttime) value ('" + Convert.ToDateTime(A) + "','" + Convert.ToDateTime(B) + "')";
i got ORA-01843 error, what I can do ?
thank's in advance
Don't use raw SQL to insert values. Use a parameterized query instead. Parse your strings into .NET DateTime (or DateTimeOffset) and TimeSpan values in the normal way, and then use something like:
string sql = "insert into MyTbl(Tdate,Ttime) values (:date, :time)";
using (OracleCommand cmd = new OracleCommand(sql, connection))
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("date", OracleType.DateTime).Value = date;
cmd.Parameters.Add("time", OracleType.IntervalDayToSecond).Value = time;
cmd.ExecuteNonQuery();
}
(Obviously adjust for the types of your actual fields.)
The error is due to the month, try:
TO_DATE(A, 'DD/MM/YYYY')
Remember that Oracle doesn't have a time-only field.
You're trying to insert a time-only field into a datetime. My guess is that the CLR is turning B into 00/00/00 22:10:39, which isn't a valid oracle date. For example:
SQL> select to_date('00/00/00', 'MM/DD/YY') from dual;
select to_date('00/00/00', 'MM/DD/YY') from dual
*
ERROR at line 1:
ORA-01843: not a valid month
Either way, Convert.ToDateTime(B) probably isn't returning the right thing.
Also, this:
"insert into MyTbl(Tdate,Ttime) value ("
should be this:
"insert into MyTbl(Tdate,Ttime) values ("
...but I'm guessing that's just a typo here.
However i tried Jon method, it didnt work for me for date also time. So i found this method for datetime. Maybe that helps someone in next future too.
OracleParameter oPrm;
oPrm = cmd.CreateParameter();
oPrm.ParameterName = ":myDate";
oPrm.OracleDbType = OracleDbType.Date;
oPrm.Value = DateTime.Now; //for date
cmd.Parameters.Add(oPrm);
I read/update data from MS Access using C#.
My code is:
public static void UpdateLastLogin(int userid, DateTime logintime) ///logintime = DateTime.Now
{
string sql = #"UPDATE [Customers] SET [LastLogin]=?";
OleDbParameter[] prms = new OleDbParameter[] {
new OleDbParameter("#LastLogin",logintime)
};
using (DAL dal = new DAL())
{
dal.UpdateRow(sql, false, prms);
}
}
When it comes to Dates, I having trouble.
This throws a "Data type mismatch in criteria expression." error.
(I removed WHERE clause for keeping it simpler)
Am I suuposed to enclose [LastLogin]=? question mark with single quotes, # signs .. does not help.
Any leads on how to handle DateTime objects with Access and OleDb provider will be greatly appreciated.
Thanks in advance.
There is a known issue with OleDb and dates. Try doing something like:
OleDbParameter p = parameter as OleDbParameter;
if (null == p)
parameter.DbType = DbType.DateTime;
else
p.OleDbType = OleDbType.Date;
Or use explicit format string:
value.ToString("yyyy-MM-dd hh:mm:ss")
I solved this using the following code
OleDbCommand cmd = new OleDbCommand(qry, cnn);
cmd.Parameters.Add("datenow", OleDbType.Date);
cmd.Parameters["datenow"].Value = DateTime.Now;
Firstly, no your SQL statement should be:
"UPDATE Customers SET LastLogin=#LastLogin"
Secondly, the reason you are receiving the date mismatch error will probably be your passing '?' as your date time into the LastLogin field instead of the actual logintime parameter.
maybe try
DateTime.Now.ToShortDateString() + ' ' + DateTime.Now.ToShortTimeString()
instead, pass it as String (and maybe enclose with # then)
Should it not be
"UPDATE Customers SET LastLogin='#LastLogin'"
And #LastLogin should be
logintime.ToString("yyyy-MM-dd hh:mm:ss")
edit
Could you not just inline the whole thing?
"UPDATE Customers SET LastLogin='" + logintime.ToString("yyyy-MM-dd hh:mm:ss") + "'"
Try setting the "DBTYPE" property of the parameter to identify it as a date, datetime or datetime2 as appropriate...
prms[0].DbType = DbType.DateTime;
There are 7 signatures to the new OleDbParameter() call, so you may change the signature instance, or just do explicitly as I sampled above since you only had 1 parameter in this case.