How do I compare a SQL Server DATETIME with the DateTime.Now value? As you can see I assigned it to a Session and tried comparing it with DateTime.Now.
string timestamp = #"SELECT sr.*, ud.* FROM SuspensionRecord sr, UserData ud WHERE sr.User_ID=#User_ID AND ud.User_ID=#User_ID";
using (SqlCommand cmd2 = new SqlCommand(timestamp, con))
{
cmd2.Parameters.AddWithValue("#User_ID", Session["UserID"].ToString());
using (SqlDataReader dr = cmd2.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
Session["suspensiondate"] = dr["End_Date_Suspension"].ToString();
}
if (Convert.ToDateTime(Session["supensiondate"]) >= DateTime.Now.Date)
{
lblMessage.Text = "The account's status is suspended.";
lblMessage.Visible = true;
}
}
}
}
You should pass in the date and do the comparison in the query instead of in c#. That is one less step. If you do want to do it in c# then use the appropriate types, do not convert the DateTime to a string and then convert it back again.
There is no need for the join (2nd table) in your query
You do not have to use a DataReader for this, you can use ExecuteScalar which returns 1 value instead.
Use Add so you can specify the correct schema types with SqlDbType and not AddWithValue
string timestamp = #"SELECT 1 FROM SuspensionRecord sr WHERE sr.User_ID = #User_ID AND supensiondate > #now";
using (SqlCommand cmd2 = new SqlCommand(timestamp, con))
{
cmd2.Parameters.Add("#User_ID", SqlDbType.Int).Value = Session["UserID"]; // do not convert to string
cmd2.Parameters.Add("#now", SqlDbType.DateTime).Value = DateTime.Now.Date;
var result = cmd2.ExecuteScalar();
if(result != null) // if null then there were no records so account is not suspended
{
lblMessage.Text = "The account's status is suspended.";
lblMessage.Visible = true;
}
}
First, your SQL is terrible.
You are returning way too much data, and you are using an implicit join (when explicit joins are a part of ANSI-SQL for almost 30 years now!)
Second, Can we stop using AddWithValue() already?
Instead of all this code you can do the entire test on SQL and return a single value:
string sql =
#"SELECT CASE WHEN EXISTS
(
SELECT 1
FROM SuspensionRecord
WHERE User_ID = #User_ID
AND End_Date_Suspension >= CAST(GETDATE() AS DATE)
) THEN 1 ELSE 0 END";
Then you can use ExecuteScalar instead of ExecuteReader, and you don't need to loop through all the irrelevant data:
using (SqlCommand cmd2 = new SqlCommand(timestamp, con))
{
cmd2.Parameters.Add("#User_ID", SqlDbType.Int).Value = Session["UserID"];
if ((int)cmd2.ExecuteScalar() == 1)
{
lblMessage.Text = "The account's status is suspended.";
lblMessage.Visible = true;
}
}
Related
I have a very silly problem. I am doing a select, and I want that when the value comes null, return an empty string. When there is value in sql query, the query occurs all ok, but if there is nothing in the query, I have to give a sqlCommand.CommandTimeout greater than 300, and yet sometimes gives timeout. Have a solution for this?
public string TesteMetodo(string codPess)
{
var vp = new Classe.validaPessoa();
string _connection = vp.conString();
string query = String.Format("SELECT COUNT(*) FROM teste cliente WHERE cod_pess = {0}", codPess);
try
{
using (var conn = new SqlConnection(_connection))
{
conn.Open();
using (var cmd = new SqlCommand(query, conn))
{
SqlDataReader dr = cmd.ExecuteReader();
if(dr.HasRows)
return "";
return codPess;
}
}
}
You should probably validate in the UI and pass an integer.
You can combine the usings to a single block. A bit easier to read with fewer indents.
Always use parameters to make the query easier to write and avoid Sql Injection. I had to guess at the SqlDbType so, check your database for the actual type.
Don't open the connection until directly before the .Execute. Since you are only retrieving a single value you can use .ExecuteScalar. .ExecuteScalar returns an Object so must be converted to int.
public string TesteMetodo(string codPess)
{
int codPessNum = 0;
if (!Int32.TryParse(codPess, out codPessNum))
return "codPess is not a number";
var vp = new Classe.validaPessoa();
try
{
using (var conn = new SqlConnection(vp.conString))
using (var cmd = new SqlCommand("SELECT COUNT(*) FROM teste cliente WHERE cod_pess = #cod_pess", conn))
{
cmd.Parameters.Add("#cod_pess", SqlDbType.Int).Value = codPessNum;
conn.Open();
int count = (int)cmd.ExecuteScalar();
if (count > 0)
return "";
return codPess;
}
}
catch (Exception ex)
{
return ex.Message;
}
}
I am using a query to select data from sql database. It has rows but data raader.Read() function returns false and rows are empty as I have checked in debugging
Code that i have been using is
public void getSale()
{
DB db = new DB();
try
{
db.cmd.CommandText = "select * from Sale where date is not null and (date between '"+StartDate+"' and '"+EndDate+"') order by date";
db.cmd.Connection = db.con;
db.con.Open();
if(db.con.State == System.Data.ConnectionState.Open)
{
db.dataReader = db.cmd.ExecuteReader();
if(db.dataReader.HasRows)
{
while(db.dataReader.Read())
{
SaleModel sm = new SaleModel();
sm.SaleId = long.Parse(db.dataReader["Id"].ToString());
sm.UserName = db.dataReader["UserName"].ToString();
sm.ItemsQuantity = int.Parse(db.dataReader["ItemsQuantity"].ToString());
sm.TotalAmount = double.Parse(db.dataReader["TotalAmount"].ToString());
sm.SubTotal = double.Parse(db.dataReader["SubTotal"].ToString());
sm.Discount = double.Parse(db.dataReader["Discount"].ToString());
sm.Completed = bool.Parse(db.dataReader["Completed"].ToString());
sm.Date = DateTime.Parse(db.dataReader["Date"].ToString());
sm.CustomerPhone = long.Parse(db.dataReader["CustomerPhone"].ToString());
SalesList.Add(sm);
}
db.con.Close();
}
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
}
}
And When I tested this query on Query editor in Visual studio rows were returned
If Anyone can help?
Why you concatenate strings to build your sql query? NEVER do that. It is a source for sql-injection and can cause issues like this. Instead use parameterized queries.
Also don't use SqlConnection wrappers like your DB class. That can cause several other issues. Instead create, open, close and dispose them where you need them, best by using the using-statament. The connection-pooling will manage the rest for you.
public List<SaleModel> GetSale(DateTime startDate, DateTime endDate)
{
string sql = #"select * from Sale
where date is not null
and date between #StartDate and #EndDate
order by date";
var salesList = new List<SaleModel>();
try
{
using (var con = new SqlConnection("insert your connection string"))
using (var cmd = new SqlCommand(sql, con))
{
cmd.Parameters.Add("#StartDate", SqlDbType.DateTime).Value = startDate;
cmd.Parameters.Add("#EndDate", SqlDbType.DateTime).Value = endDate;
con.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
SaleModel sm = new SaleModel();
sm.SaleId = long.Parse(reader["Id"].ToString());
sm.UserName = reader["UserName"].ToString();
sm.ItemsQuantity = int.Parse(reader["ItemsQuantity"].ToString());
sm.TotalAmount = double.Parse(reader["TotalAmount"].ToString());
sm.SubTotal = double.Parse(reader["SubTotal"].ToString());
sm.Discount = double.Parse(reader["Discount"].ToString());
sm.Completed = bool.Parse(reader["Completed"].ToString());
sm.Date = DateTime.Parse(reader["Date"].ToString());
sm.CustomerPhone = long.Parse(reader["CustomerPhone"].ToString());
salesList.Add(sm);
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
}
return salesList;
}
I'm pretty sure that this works(f.e. can be a localization issue).
Side-note: a method GetSale should return a List<SaleModel> but not fill one. You should also pass the parameters as DateTime to the method. I've changed it in my code sample.
This is a much better way to structure you code, and there's a good chance it will fix your issue, too:
//accept the date values as parameter arguments, return the result.
// Do NOT mess about with variables at the global or class scope.
public IEnumerable<SalesModel> getSale(DateTime StartDate, DateTime EndDate)
{
string sql = "select * from Sale where date is not null and (date between #StartDate and #EndDate) order by date";
//DON'T abstract SqlCommand/SqlConnection. DO abstract your connection string.
//Also, don't bother with the try/catch at this level. You can't really do anything with it here, so worry about the exception in calling code.
using (var cn = new SqlConnection(DB.ConnectionString))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("#StartDate", SqlDbType.DateTime).Value = StartDate
cmd.Parameters.Add("#EndDate", SqlDbType.DateTime).Value = EndDate
cn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while(rdr.Read())
{
var sm = new SaleModel();
//If you have good schema design, these values are **already** in the correct type.
// The old code forces an expensive conversion to string, following by an expensive parse back to the type it already had.
// We can do MUCH better.
sm.SaleId = (long)rdr["Id"];
//but it is okay for types that are *already* strings
sm.UserName = rdr["UserName"].ToString();
sm.ItemsQuantity = (int)rdr["ItemsQuantity"];
sm.TotalAmount = (double)rdr["TotalAmount"]);
sm.SubTotal = (double)rdr["SubTotal"];
sm.Discount = (double)rdr["Discount"];
sm.Completed = (bool)rdr["Completed"];
sm.Date = (DateTime)rdr["Date"];
sm.CustomerPhone = (long).rdr["CustomerPhone"];
yield return sm;
}
}
}
}
Here it is again without all the extra comments. The point here is this is still less code than the original that used string concatenation, and it took less than 10 minutes to write. Good code doesn't necessarily take longer.
public IEnumerable<SalesModel> getSale(DateTime StartDate, DateTime EndDate)
{
string sql = "select * from Sale where date is not null and (date between #StartDate and #EndDate) order by date";
using (var cn = new SqlConnection(DB.ConnectionString))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("#StartDate", SqlDbType.DateTime).Value = StartDate
cmd.Parameters.Add("#EndDate", SqlDbType.DateTime).Value = EndDate
cn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while(rdr.Read())
{
var sm = new SaleModel();
sm.SaleId = (long)rdr["Id"];
sm.UserName = rdr["UserName"].ToString();
sm.ItemsQuantity = (int)rdr["ItemsQuantity"];
sm.TotalAmount = (double)rdr["TotalAmount"]);
sm.SubTotal = (double)rdr["SubTotal"];
sm.Discount = (double)rdr["Discount"];
sm.Completed = (bool)rdr["Completed"];
sm.Date = (DateTime)rdr["Date"];
sm.CustomerPhone = (long).rdr["CustomerPhone"];
yield return sm;
}
}
}
}
Note that I return an IEnumerable rather than a List. If you really need a List (tip: you probably don't, and sticking with IEnumerable is faster), you can just call ToList() on the result.
don't see any issue except that you are using date which is a reserve word and not your actual column name. Change your query to be
db.cmd.CommandText = "select * from Sale where [date] is not null and ([date] between '"+StartDate+"' and '"+EndDate+"') order by [date]";
Good day!
It's taking me hours why my query returns a true even it's false.
Here's my code.
public SqlDataReader Check(BEL bel) {
SqlCommand cmd = new SqlCommand();
cmd.Connection = dbcon.getcon();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT SUM(Total) as OverallTotal FROM table WHERE Id=#Id AND DateFrom=#From AND DateTo=#To AND Status='Without'";
cmd.Parameters.AddWithValue("#Id",bel.CLEmpID);
cmd.Parameters.AddWithValue("#From", bel.CLPayrollFrom);
cmd.Parameters.AddWithValue("#To", bel.CLPayrollTo);
SqlDataReader dr = cmd.ExecuteReader();
return dr;
}
Suppose the parameterized values are:
#Id = 0001
#From = 1/28/2016
#To = 1/29/2016
Here's my method calling the datareader
SqlDataReader drCheck;
drCheck = bal.Check(bel);
if (drCheck.HasRows == true)
{
drCheck.Read();
// I'm inside the computation of OverallTotal
}else{
drCheck.Close();
// I'm out
}
drCheck.Close();
The problem is, when the value of my "To", for instance, is 1/30/2016, it suppose to go to the false which is out of the true condition but it is not.
Please help. Thanks in advance
In your query, you are have aggregate function. Whether your from & to returns no rows, as you have aggregate function, you always get one row with value at least zero.
In your case you don't need a Reader, you can use ExecuteScalar:
public decimal? Check(BEL bel)
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = dbcon.getcon();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT SUM(Total) as OverallTotal FROM table WHERE Id=#Id " +
"AND DateFrom=#From AND DateTo=#To AND Status='Without'";
cmd.Parameters.AddWithValue("#Id", bel.CLEmpID);
cmd.Parameters.AddWithValue("#From", bel.CLPayrollFrom);
cmd.Parameters.AddWithValue("#To", bel.CLPayrollTo);
object obj = cmd.ExecuteScalar();
decimal? value = null;
if (obj != DBNull.Value)
value = Convert.ToDecimal(obj);
return value;
}
decimal? total = bal.Check(bel);
if (total.HasValue)
{
// do something with the total.Value
}
else
{
}
Look at simple example
SELECT SUM(total1) as tt1, SUM(total2) AS tt2, COUNT(*) AS [Nbr of rows]
FROM (
SELECT 10 AS total1, CAST(NULL AS INT) total2 --
) t
--WHERE 1=2
Generally when the SUMmed column is nullable only COUNT(*) will tell the difference are there any rows selected or no rows selected.
Your query always returns a value even if there are no matching records because you are summing them, so you get NULLin case of no records and in the case of all matching records' values are NULL. You'll get 0 if there are records and the sum-result is 0(including NULL values which will be counted as 0).
You could use following approach that uses a different query to return both informations:
public bool GetOverAll(int id, DateTime payrollFrom, DateTime payrollTo, out double? overall)
{
overall = null;
string sql = #"
;WITH Data AS(
SELECT t.*
FROM table
WHERE Id = #Id
AND DateFrom = #From
AND DateTo = #To
AND Status = 'Without'
)
SELECT HasRows = CAST(CASE WHEN EXIST( SELECT 1 FROM CTE )
THEN 1 ELSE 0 END AS bit),
OverallTotal = SUM(Total)
FROM CTE";
using (var con = new SqlConnection("connectionstring"))
using (var cmd = new SqlCommand(sql, con))
{
cmd.Parameters.AddWithValue("#Id", id);
cmd.Parameters.AddWithValue("#From", payrollFrom);
cmd.Parameters.AddWithValue("#To", payrollTo);
con.Open();
using (var rd = cmd.ExecuteReader())
{
if (rd.Read())
{
bool hasRows = rd.GetBoolean(0);
if (!rd.IsDBNull(1))
overall = rd.GetDouble(1);
return hasRows;
}
else
{
throw new Exception("This should never be the case!");
}
}
}
}
You now know if there were matching records or not:
double? overall;
bool hasRows = GetOverAll(id, payrollFrom, payrollTo, out overall);
if(hasRows && overall.HasValue)
{
// matching records and the sum of these values was not NULL (possible if nullable column and all values were NULL)
double total = overall.Value;
}
I'm trying to return a query (in a gridview in ASP.NET) WHERE Time >= DateTime.Now.Add(-60). The WHERE clause has been giving me no end of difficulties.
DateTime pastTime = DateTime.Now.Add(-60);
ds_DB.SelectCommand = "SELECT * FROM [vPurchaseTotals] WHERE [TimeOfTransaction] >= " + pastTime;
My issue is getting pastTime to convert properly, so it only returns the newer data. [TimeOfTransaction] is a time(7) data type in the table.
How do I parse C#'s DateTime to SQL Server's Time?
Here, try this:
using(SqlConnection conn = new SqlConnection(yourConnectionString))
{
DateTime pastTime = DateTime.Now.Add(-60);
ds_DB.SelectCommand = #"SELECT * FROM [vPurchaseTotals]
WHERE [TimeOfTransaction] >= #PastTime";
SqlCommand cm = conn.CreateCommand();
cm.CommandText = ds_DB.SelectCommand;
cm.Parameters.Add("#PastTime", SqlDbType.Time).Value = pastTime.TimeOfDay; //For comparison with TSQL TIME type
try
{
conn.Open();
// Do what you need to do here.
}
catch(SqlException e)
{
// Handle Exception
}
finally
{
conn.Close();
}
}
Just for future reference, you should always parameterize your queries. It ends up being a lot safer and cleaner/easier to read and adjust.
EDIT: Are you using a SqlDataAdapter class? Is that what ds_DB is an instance of? I would personally just use a string value for your query and then implement the SqlDataAdapter like this:
try
{
conn.Open();
using(SqlDataAdapter da = new SqlDataAdapter(cm))
{
da.Fill(DataTable dt);
}
}
I have a simple database that I am using. It contains two entries for users which is a user with UserID 1 and IsAdmin 0 and another with UserID 3041234567 and IsAdmin of 1. The only fields in the database is a string UserID and a bit IsAdmin. I am reading from the database with the following code:
SqlConnection conn = new SqlConnection(Properties.Settings.Default.Conn);
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM Users WHERE UserID = " + t.Text.ToString(), conn);
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
user.UserID = reader["UserID"].ToString();
user.IsAdmin = Convert.ToBoolean(reader["IsAdmin"]);
}
}
conn.Close();
If I enter the number 3041234567 as the UserID everything works perfectly, but If I enter the number 1 I get an exception saying that "The conversion of the nvarchar value '3041234567' overflowed an int column."
If I set a breakpoint and watch the while(reader.read()) loop the loop iterates through fine and sets the user.UserID = 1 and the user.IsAdmin = false. The exception is thrown when the loop begins to iterate a second time. I guess I have a couple of questions:
Why is the loop iterating a second time?
How is the ID 3041234567 being returned with the sql command "SELECT * FROM Users WHERE UserID = 1"
What is the int column that is being overflowed?
Well, since
3041234567 > int.MaxValue ( == 2147483647)
you've got an overflow; if you want some kind of integer value, however, try long (which is 64 bit long):
long value = Convert.ToInt64(reader["UserID"]);
Something like this:
// Wrap IDisposable into using
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.Conn)) {
conn.Open();
// Make sql
// 1. Readable
// 2. Parametrized
// 3. Avoid * in select
String sql =
#"select UserID,
IsAdmin
from Users
where UserID = #prm_UserId";
// Wrap IDisposable into using
using (SqlCommand cmd = new SqlCommand(sql, conn)) {
// Explicit data type will be better here (Add Parameter with type)
// but I don't know it
cmd.Parameters.AddWidthValue("prm_UserId", t.Text);
// Wrap IDisposable into using
using (SqlDataReader reader = cmd.ExecuteReader()) {
// You don't want to iterate the whole cursor, but the first record
if (reader.Read()) {
//TODO: Make UserID being "long"
user.UserID = Convert.ToInt64(reader["UserID"]);
user.IsAdmin = Convert.ToBoolean(reader["IsAdmin"]);
}
}
}
}