Select a date range from a timestamp column - sql

Currently my table has a column to store date and time. The data type of that column is timestamp without time zone. So it has values in the format '2011-09-13 11:03:44.537'.
I need to retrieve rows with respect to the date. If I use:
select * from table where mdate >= '2011-09-13 11:03:44.537'
and mdate <= '2011-09-12 11:03:44.537'
it will provide the values which are in between '2011-09-13 11:03:44.537' and '2011-09-12 11:03:44.537'.
But if I am going with:
select * from table where mdate >= '2011-09-13 00:00:00.0'
and mdate <= '2011-09-12 00:00:00.0'
without date, month and seconds, It is not displaying any rows.
How to fetch values from this table with respect to the date (only with date, ignoring hour, minutes and seconds)?
Even, the column has date with timestamp, I need to search them only with date (ignoring timestamp or making the hour, minutes and seconds to 0 such as '2011-09-13 00:00:00.0').

If you are going to cast the timestamp values of the field to date, as suggested in another answer, performance will degrade because every single value in the column needs to be cast for comparison and simple indexes cannot be used. You would have to create a special index on the expression, like so:
CREATE INDEX some_idx ON tbl (cast(mdate AS date));
In this case the query should also be simplified to:
SELECT * FROM tbl
WHERE mdate::date = '2011-09-12'::date; -- 2nd cast optional
However, as far as I can see, your problem is a simple typo / thinko in your query:
You switched upper & lower boundaries. Try:
SELECT * FROM tbl
WHERE mdate >= '2011-09-12 00:00:00.0'
AND mdate <= '2011-09-13 00:00:00.0';
Or, to simplify your syntax and be more precise:
SELECT * FROM tbl
WHERE mdate >= '2011-09-12 00:00'
AND mdate < '2011-09-13 00:00';
There is no need to spell out seconds and fractions that are 0.
You don't want to include 2011-09-13 00:00, so use < instead of <=.
Don't use BETWEEN here, for the same reason:
WHERE mdate BETWEEN '2011-09-12 00:00' AND '2011-09-13 00:00'
This would include 00:00 of the next day.
Also be aware that a column of type timestamp [without time zone] is interpreted according to your current time zone setting. The date part depends on that setting, which should generally work as expected. More details:
Ignoring time zones altogether in Rails and PostgreSQL

Just treat the timestamp as a date:
select *
from table
where mdate::date >= DATE '2011-09-12'
and mdate::date <= DATE '2011-09-13'
The expression mdate::date will cast the timestamp to a date type which will remove the time part from the value.
DATE '2011-09-13' is a (standard) DATE literal which is a bit more robust than simply writing '2011-09-13' as it isn't affected by any language settings.

Related

how to select all entries having date 25-11-20 in oracle 11g?

sql table
here in the table above named carpooling contains a column name start_on which has date time as timestamp i have to write a query to select all the rows having date as 25-11-20 using to_char and to_date.
You write a timestamp literal like this:
timestamp '2020-11-25 00:00:00'
so the full filtering condition will be
where start_on >= timestamp '2020-11-25 00:00:00'
and start_on < timestamp '2020-11-26 00:00:00'
Note that dates and timestamps are different in Oracle, and dates include times down to the second (this is for historical reasons - originally there was only the date type, and timestamp was added much later).
Use the TRUNC function, along with date and interval literals:
SELECT *
FROM CARPOOLING
WHERE START_ON BETWEEN DATE '2020-11-25'
AND (DATE '2020-11-26' - INTERVAL '0.000001' SECOND)
You can simply use to_date, but it's recommended to remove the time when comparing the dates. Otherwise, rows having the same date, but a different time will not be selected. Removing the time can be done using TRUNC.
So you can do something like this:
SELECT * FROM carpooling
WHERE TRUNC(start_on) = TO_DATE('2020-11-25','yyyy.mm.dd');
If you don't want to check the 25th of November 2020, but another data, change the date to match your goal.

TIMESTAMP To DATE in Oracle SQL

I have a column called Create_Date which has data in the format like 19-JUN-18 10.27.00.000000000 PM and data type is TIMESTAMP(6).
I am trying to look at date range like yesterday's date or between two dates in Create_Date without using TO_DATE(TO_CHAR(P.CREATE_DATE_TIME,'dd/mon/yy')) and entering the value as '19-JUN-18'.
I want to use Create_Date=SYSDATE-1 OR Create_Date=CURRENT_DATE-1 instead to filter on yesterdays date. Or Use Create_Date>=SYSDATE or Create_Date>=CURRENT_DATE to look at dates greater than or equal to today.
Can someone help?
You could use TRUNC:
SELECT *
FROM tab
WHERE Create_Date >= TRUNC(SYSDATE,'DD') -- -1
-- or between to dates (using date literals)
WHERE Create_Date >= DATE 'yyyy-mm-dd'
AND Create_Date < DATE 'yyyy-mm-dd'
As it's a timestamp I'd cast the truncated (to midnight) current date to a timestamp for clarity; Oracle will use an index on that column even if you leave it as a date, but it doesn't hurt to make it explicit:
where create_date >= cast(trunc(sysdate) as timestamp)
The trunc() function defaults to truncating to midnight; you can explicitly include 'DD' as a second argument if you prefer (for even more clarity, though some would see it as noise).
If you want a range, say yesterday:
where create_date >= cast(trunc(sysdate) - 1 as timestamp)
and create_date < cast(trunc(sysdate) as timestamp)
If you want to specify other dates then you can use timestamp literals, e.g. to see everything for May:
where create_date >= timestamp '2018-05-01 00:00:00'
and create_date < timestamp '2018-06-01 00:00:00'

Sql strictly more than query

I'm in PostgreSQL.
I need to print all mailing with creation date strictly more that 2015-04-04. I tried the following queries:
SELECT *
FROM mailing.mailing
WHERE creation_date > '2015-04-04';
and
SELECT *
FROM mailing.mailing
WHERE creation_date >= '2015-04-04';
But they produced the same result set(including '2015-04-04'). Is it possible to write such a query without explicitly saying WHERE creation_date >= '2015-04-05';
UPD: The column's type is timestamp without time zone.
If your creation_date field is of type datetimetry comparing it to '2015-04-04 23:59:59' instead, as '2015-04-04 08:30:00' seems to be greater than '2015-04-04'.
Assuming your default date format for your database is 'YYYY-MM-DD' and creation_date field is a date type, your query will actually be converted automatically to something like:
SELECT *
FROM mailing.mailing
WHERE creation_date > to_date('2015-04-04', 'YYYY-MM-DD');
The date value you have provided represents the first second of that day, that's why you see no difference between your queries. (Your first query would exclude the first second of the day though.)
What you could do to avoid this is:
where creation_date >= to_date('2015-04-05 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
or
where date_trunc(creation_date-1) = '2015-04-04'

Date range in select

I have this table
CREATE TABLE Table1 (
MY_ID INTEGER NOT NULL,
SCAN_TIME TIMESTAMP NOT NULL,
WORKCELL_ID SMALLINT
);
My problem when I use select SQL to get records between two dates I get empty result if the user select the same date for the two dates
For ex:
Select * from Table1
where SCAN_TIME between '20.9.2014' and '20.9.2014'
Although there are records in that date '20.9.2014' but I get empty result and I get results only if I increase the second date by one day to be '21.9.2014' !! why is that and how I should fix ?
The problem is that you used timestamp as the type, and things messed up due to the time portion. Try to use Date.
When you said between 2014-09-20 and 2014-09-20, you are actually saying between 2014-09-20 midnight and 2014-09-20 midnight, apparently nothing falls in between other than the exact moment of midnight.
If you cannot control the table structure, do what PM 77-1 suggested in his comment below - use cast to cast timestamp into date:
select 1 from table1
where cast(scan_time as date) between 'someday1' and 'someday2';
A TIMESTAMP contains both a date and a time. Since you're not specifying the time in your WHERE clause, it's using the beginning of the day for both times. So you're actually writing the equivalent of:
WHERE SCAN_TIME between '20.9.2014 00:00:00' and '20.9.2014 00:00:00'
Unless the time part of the timestamp is actually 00:00:00, it won't satisfy this criterion. You should convert the timestamp to a date, or specify the times in your range, e.g.
WHERE SCAN_TIME between '20.9.2014 00:00:00' and '20.9.2014 23:59:59'

SQL "between" not inclusive

I have a query like this:
SELECT * FROM Cases WHERE created_at BETWEEN '2013-05-01' AND '2013-05-01'
But this gives no results even though there is data on the 1st.
created_at looks like 2013-05-01 22:25:19, I suspect it has to do with the time? How could this be resolved?
It works just fine if I do larger date ranges, but it should (inclusive) work with a single date too.
It is inclusive. You are comparing datetimes to dates. The second date is interpreted as midnight when the day starts.
One way to fix this is:
SELECT *
FROM Cases
WHERE cast(created_at as date) BETWEEN '2013-05-01' AND '2013-05-01'
Another way to fix it is with explicit binary comparisons
SELECT *
FROM Cases
WHERE created_at >= '2013-05-01' AND created_at < '2013-05-02'
Aaron Bertrand has a long blog entry on dates (here), where he discusses this and other date issues.
It has been assumed that the second date reference in the BETWEEN syntax is magically considered to be the "end of the day" but this is untrue.
i.e. this was expected:
SELECT * FROM Cases
WHERE created_at BETWEEN the beginning of '2013-05-01' AND the end of '2013-05-01'
but what really happen is this:
SELECT * FROM Cases
WHERE created_at BETWEEN '2013-05-01 00:00:00+00000' AND '2013-05-01 00:00:00+00000'
Which becomes the equivalent of:
SELECT * FROM Cases WHERE created_at = '2013-05-01 00:00:00+00000'
The problem is one of perceptions/expectations about BETWEEN which does include BOTH the lower value and the upper values in the range, but does not magically make a date the "beginning of" or "the end of".
BETWEEN should be avoided when filtering by date ranges.
Always use the >= AND < instead
SELECT * FROM Cases
WHERE (created_at >= '20130501' AND created_at < '20130502')
the parentheses are optional here but can be important in more complex queries.
You need to do one of these two options:
Include the time component in your between condition: ... where created_at between '2013-05-01 00:00:00' and '2013-05-01 23:59:59' (not recommended... see the last paragraph)
Use inequalities instead of between. Notice that then you'll have to add one day to the second value: ... where (created_at >= '2013-05-01' and created_at < '2013-05-02')
My personal preference is the second option. Also, Aaron Bertrand has a very clear explanation on why it should be used.
Just use the time stamp as date:
SELECT * FROM Cases WHERE date(created_at)='2013-05-01'
I find that the best solution to comparing a datetime field to a date field is the following:
DECLARE #StartDate DATE = '5/1/2013',
#EndDate DATE = '5/1/2013'
SELECT *
FROM cases
WHERE Datediff(day, created_at, #StartDate) <= 0
AND Datediff(day, created_at, #EndDate) >= 0
This is equivalent to an inclusive between statement as it includes both the start and end date as well as those that fall between.
cast(created_at as date)
That will work only in 2008 and newer versions of SQL Server
If you are using older version then use
convert(varchar, created_at, 101)
You can use the date() function which will extract the date from a datetime and give you the result as inclusive date:
SELECT * FROM Cases WHERE date(created_at)='2013-05-01' AND '2013-05-01'
your code
SELECT * FROM Cases WHERE created_at BETWEEN '2013-05-01' AND '2013-05-01'
how SQL reading it
SELECT * FROM Cases WHERE '2013-05-01 22:25:19' BETWEEN '2013-05-01 00:00:00' AND '2013-05-01 00:00:00'
if you don't mention time while comparing DateTime and Date by default hours:minutes:seconds will be zero in your case dates are the same but if you compare time created_at is 22 hours ahead from your end date range
if the above is clear you fix this in many ways like putting ending hours in your end date eg BETWEEN '2013-05-01' AND ''2013-05-01 23:59:59''
OR
simply cast create_at as date like cast(created_at as date) after casting as date '2013-05-01 22:25:19' will be equal to '2013-05-01 00:00:00'
Dyamic date BETWEEN sql query
var startDate = '2019-08-22';
var Enddate = '2019-10-22'
let sql = "SELECT * FROM Cases WHERE created_at BETWEEN '?' AND '?'";
const users = await mysql.query( sql, [startDate, Enddate]);
Even though it is inclusive, as per Aaron Bertrand suggestion (read more about it here)
don't use BETWEEN for date/time ranges.
Apart from other good answers around here, one can also use DATEADD (to add a number of days to a given date) as follows
SELECT * FROM Cases WHERE created_at >= '2013-05-01' AND created_at < DATEADD(day, 1, '2013-05-01')