I have a database with employee information and a program, which is supposed to retrieve data from this database.
The database structure seems like this:
ID | Date | signedIn | SignedOut
1 01-10-2012 08:00:00 16:00:00
1 14-10-2012 08:00:00 16:00:00
1 13-09-2012 08:00:00 16:00:00
When I then try to retrieve data between 01-10-2012 and 15-10-2012 I want go get only the first two rows. So I get a total amount of hours worked to 16.
But right now I get the total amount to 24, because it also retrieves the last one, even though it is from last month
sql sentence:
SELECT Info.UserID, Info.SurName, Info.FirstName, timetabel.Date,
FROM Info
INNER JOIN timestabel
ON Info.UserID = Bruger_tidstabel.UserID
WHERE Info.UserID = '1'
AND timetabel.Date >= '01-10-2012'
AND timetabel.Date <= '14-10-2012'"
the sentence works, so it can retrieve data from database.
Is there any way to tell the database, I am working with dates, so it will only retrieve data between two surden dates??
Try the BETWEEN Statement, like:
"... WHERE Info.UserID = '1' AND (timetabel.Date BETWEEN '01-10-2012' AND '14-10-2012')"
Check with or without the () ..
Also check if the date pattern is correct, depends on your database.
You can use the BETWEEN operator, it is used in a WHERE clause to select a range of data between two values.
SELECT column_name(s)
FROM table_name
WHERE column_name
BETWEEN value1 AND value2
It is good idea your table field Date to be in date or time stamp format. Also, the year goes on front of the date format, like this:
SELECT Info.UserID, Info.SurName, Info.FirstName, timetabel.Date, FROM Info INNER JOIN timestabel ON Info.UserID = Bruger_tidstabel.UserID WHERE Info.UserID = '1' AND timetabel.Date BETWEEN '2012-10-01' AND '2012-10-14'
You always need to be careful when representing dates as strings since as Christian says, they are not always treated as expected. Ensure you use datetime types or use one of the date functions (DATEADD, DATEDIFF, etc) so that you are comparing dates with dates!
Unfortunately the SQL will often run without error but what it has intepreted from your SQL is not always as expected!
While not answering your question directly (other answered already), I would like to warn you from a common pitfall when working with date ranges.
timetabel.Date <= '14-10-2012'
What happens if the date/time stored in timetabel.Date is 14-10-2012 08:30? This date will be excluded. Personally I prefer to use this safer test
timetabel.Date < '15-10-2012'
this is equivalent to the above one (except for the time part of cause). So instead of comparing
table.column <= date
I compare
table.column < (date + one day)
Related
I have the following datetime range:
22/07/2021 07:00:52 (start date)
22/07/2021 07:01:00 (end date)
I want all the data between this range including the right hand boundary.
My linq to SQL query:
Select * from tableName where CreatedAt >= startDate and CreateAt <= endDate
The issue here with the query is I am unable to get the record whose CreatedAt= 22/07/2021 07:01:00 (end date). If I do AddMinutes(1) to the endDate, I get the required datas but I also get the data greater than endDate.
For example data having following Created At dates
22/07/2021 07:01:15
22/07/2021 07:01:20
which is faulty.
How do I include the right boundary in the range comparison for datetime?
I have tried removing the miliseconds from the database record as:
select * from Custom_Devices
where
DATEADD(ms, -DATEPART(ms, CreatedAt), CreatedAt) >= '2019-07-29
19:00:00'
and
DATEADD(ms, -DATEPART(ms, CreatedAt), CreatedAt) <=
'2019-07-29 19:01:00'
Attaching a screenshot of the output:
Expected output:
Update: CreatedAt column is a datetime2 column in database.
f I do AddMinutes(1) to the endDate
Not sure why you'd add a whole minute when the problem is caused by additional milliseconds and can be solved by going up a second..
Do you actually want to keep the milliseconds on the dates? Is it any use to you to know that the event occurred at 12:34.56.789 rather than 12:34:56? If not, make the column a datetime2(0) to discard the milliseconds permanently
Otherwise I recommend the route several other people are also advocating and do your LINQ like
context.Whatever.Where(x => x.CreatedAt >= startDate && x.CreatedAt < endDate.AddSeconds(1))
The "less than" is vital. A "less than 12:34:57" will get 12:34:56.999999... which appears to be what you want with your "less than or equal to 12:34:56"
If you're struggling to understand why milliseconds cause a problem, think of dates like numbers - if you have a number 1.222222 and you ask the db for "less than or equal to 1.2" the DB doesn't auto-round the 1.222222 down to 1 decimal place and then go "oh it's equal to 1.2" and return it. It just goes "1.222222 is not less than or equal to 1.2, don't return it"
Over time for question like this you'll always get someone who says "just cast it to.." or "run this to calculate a new date to remove the milliseconds..." - don't; if you write a query that manipulates the table data, that manipulation has to be performed every time the data is queried. It typically kills the ability for the db to use an index on the column too (the db will probably switch to running the manipulation on every value in the index, every time) which means the query is massively more resource intensive.
Always consider manipulating table data in a where clause as an absolute last resort. If there is no other way and the query will be heavily used, look at adding some kind of calculated column to the table and index it so that, conceptually, the result of the manipulation you're carrying out is done once and an index on it can be used
In my Windows Form C# Application, I am inserting the record into the SQL server database. Along with other fields, I am also inserting both the current date and current time using the following format:
DateTime currentDate = DateTime.Now;
string SaleDate = currentDate.ToString("dd-MM-yyyy");
DateTime currentTime = DateTime.Now;
string SaleTime = currentTime.ToString("hh:mm:ss tt");
Which works fine and the records are inserted successfully with Date and Time format like .
However, when I select records between two dates, I am unable to perform this operation. I am sure that there is no problem in this custom format of my date because I have edited the same format several times and even I have saved the date in its default format but still I am unable to select the target records (between two dates)
I am using the following select query in my application to select records from the view vAllSales which results in selecting either all the records or records whose SaleDate does not meet the specified filter criteria:
select * from vAllSales where SaleDate >= '20-04-2019' and SaleDate <= '30-04-2019'"
I have tried the following queries in my SQL server as well to inspect the cause:
1.
select * from vAllSales where SaleDate between '21-04-2019' and '09-05-2019'
The above query does not return any value. Like
2.
select * from vAllSales where SaleDate >= '21-04-2019'
The above query select only a few records. Because 21-04-2019 is the initial SaleDate and the query should return all of the Sales but it only returns a few records, like .
Is there any issue with the specified date format within my code? Or do I have to work on improving my queries? I need a more professional and reliable approach for this case.
You should store your date and time as datetime2 objects in your database.
It will give you the benefits of:
better sorting: (your current string format does not allow a natural sort)
better performance; since your date and times are represented as numbers in stead of strings
easier to handle in code and queries: since it maps directly to a C# DateTime object.
For more info on database types see:
https://learn.microsoft.com/en-us/sql/t-sql/data-types/datetime2-transact-sql?view=sql-server-2017
And perhaps:
https://learn.microsoft.com/en-us/sql/t-sql/data-types/time-transact-sql?view=sql-server-2017
If you absolutely must use a string to represent your date, make sure it's in the sort-able ISO format.
YYYY-MM-DD
due to the nature of this format it's lexicographical sort-able as a string type.
You are trying to apply logical operations to string values. What will here happen is lexicographical comparing. (left to right).
So you better use correct data types to store data in table.
But If you really want to store date as a string, you have to cast them to proper data types before comparison.
select * from vAllSales where CAST(SaleDate AS DATE) >= '21-04-2019'
Keep note that ms sql server uses single quotes for pass datetimes. That doesn't mean those are strings or varchar
this is my first question so pardon any mistakes that might occurs :)
I made a C# program that collects data from SQL Server Database using Datatables, and then export the results to Excel spreadsheets using Interop.
The program itself runs well and doing as it should; however, I found some bugs when it tries to select data with Date columns less than or equal to i.e. 2014-05-31 23:59:59.
Supposed I tried to get all data up to May 1st 2014.
My code first initiates the "Start Date" parameter for the SQL Command later used like this:
var firstDay = new DateTime(today.Year, today.Month, 1); //2014-05-01 00:00:00`
based on firstDay, it initiates the date for the parameter
var periodTo = firstDay.AddSeconds(-1);`
I debugged and got the time I wanted: 2014-04-30 23:59:59
After adding some more parameters for the data criteria, it executes the method to run the query using the parameters supplied.
queryResult = medicore.GenerateRegister(ConfigurationManager.AppSettings["queryDir"], ConfigurationManager.AppSettings["queryName"]);`
The periodTo parameter will be mapped to #EDate variable in the SQL Script. #EDate is declared as Datetime. The #Edate comes into play here:
Select columns
From tables
Where Voucher.Date <= #EDate
which I suppose, the script will be looks like Where Voucher.Date <= '2014-04-30 23:59:59'
The problem is, the result in the Excel file generated also consists of data from '2014-05-01', which is not supposed to be there...at least based on the criteria I set.
Is there some kind of rounding happened between C# and SQL Server?
Thanks!
The reason for this is probably that Voucher.Date is a SMALLDATETIME, therefore you are implicitly converting '2014-04-30 23:59:59' to a SMALLDATETIME:
SET DATEFORMAT MDY;
SELECT CONVERT(SMALLDATETIME, '2014-04-30 23:59:59')
Which gives '2014-05-01'.
Why not just use the Less than operator, instead of less than or equal to?
SET DATEFORMAT MDY;
SELECT ...
WHERE Voucher.Date < '2014-05-01';
N.B I have explcilty stated the DATEFORMAT because yyyy-MM-dd (despite being an ISO standard) is not culture invariant for the DATETIME and SMALLDATETIME data types in SQL Server, and if (like me) you are in a country where the default date format is DMY then SELECT CONVERT(SMALLDATETIME, '2014-04-30') will give you a conversion error. yyyyMMdd is the only culture invariant date format for these two types.
An excellent, and very relevant article to read is Aaron Bertrand's Bad habits to kick : mis-handling date / range queries
I have been given a table that has over 2 Billion rows in it. It has a field for time entered but the creator of the table made this field a string field. It also does not follow normal date-time conventions.
I have been tasked to create a new field that is a datetime type field containing the same time but converted to be proper format so that queries can be run on it.
Currently I have written a C# console application that SELECTS the top 100000 rows that have not been updated yet and row by row converts the string to a time. It then updates each of the rows.
This process works but it is slow and time is of the essence. I can run multiple copies of my program and am trying to come up with a solution to somehow run the program multiple times and make sure each copy of the program is updating different rows.
Ideas so far:
instead of selecting top 100000 rows, select 1000000 random rows. (there may be some overlap but it would get the job done)
this table has an id field. I could do a select where id modulo 2 == 0 for one program, id % 2 != 0 for another (this could continue for prime numbers etc.)
get rows only within an id range that is specified for each copy of the program I have running
add a locked column to tell my program that a field is currently locked (which would represent that it is being processed)
Can anyone provide a better suggestion? Improve on one of mine?
Thanks.
UPDATE: an example of my existing time string is 12/Nov/2014:08:52:22 and it needs to be converted to 2014-11-12 08:42:22
Use LINQ to SQL and only pull a certain amount of records at a time.
Your code would look something along these lines:
using (var db = new MyDbContext())
{
var results = db.GetResultsFromDatabase();
int take = 100;
int processed = 0;
while(processed < results.Count())
{
var set = results.Skip(processed).Take(take);
set.ForEach(s => {
// update the date
}
processed += take;
}
db.SubmitChanges();
}
So here is my solution, I have no idea how efective is for 2mil rows, in case you want to do it in SQL.
Declare #string varchar(50) = '12/Nov/2014:08:52:22'
SELECT CONVERT(datetime,REPLACE(SUBSTRING(#string,0,CHARINDEX ( ':' ,#string , 0)),'/',' ')
+' '+
SUBSTRING(#string,CHARINDEX ( ':' ,#string , 0)+1,LEN(#string)),120)
Let me explain you a bit the code
REPLACE(SUBSTRING(#string,0,CHARINDEX ( ':' ,#string , 0)),'/',' ')
replaces the "/" chars from the date and returns 12 Nov 2014
SUBSTRING(#string,CHARINDEX ( ':' ,#string , 0)+1,LEN(#string)),120)
get the time without the ":" between the date and time from your initial string.
Finally added a space between this two string manipulations and converted it to datetime.
Output for the query above : '2014-11-12 08:52:22.000'
Just do it inside SQL instead of reading the entire database and working it.
use the following :
UPDATE <TableName>
SET <dateTime-Date> = CONVERT(datetime, <string-Date>)
check this site for any format specifications you would like :
SQL Datetime Conversion
In UI I have two date picker fields that user can select start and end date of his search. ( No time value entry, just date part) So for example he can enter the same date for both start and end of his criteria if he wants to only see the records for that one specific date.
Now in SQL Server those columns are stored as DateTime fileds with values like
'2013-04-04 10:48:02.830'
So because it keeps the time part in SQL Server too, then my searches return no result when the start and end date is the same in C# part.
How can I fix this on C# side? ( I am assuming there is a use case for the time part that we keep in SQL Server in some other part of the application so don't want to mess with back-end section).
So: SQL Server has values like '2013-04-04 10:48:02.830'
C# is passing values like {11/26/2011 12:00:00 AM}
And when the start and end date are the same, we get no results.
Assuming you have code on the back end that go to SQL Server for you, instead of having a UI that is data bound:
You simply take the two values you get from the UI and modify them as needed:
DateTime from = originalFromDate.Date;
DateTime to = originalToDate.Date.AddDays(1).AddSeconds(-1);
and now if you search for anything that is between from and to, you'll find your records:
(in case of LINQ:)
var query = queryUntilNow.Where(x => x.Date >= from && x.Date <= to);