Different query results while using DATE_TRUNC function in WHERE clause - sql

I have a SQL query which gives different set of result when I use condition
DATE_TRUNC('DAY', timestamp) BETWEEN date_trunc('DAY', NOW()) - interval '14' day AND date_trunc('DAY', NOW())
and a different result when I use condition
timestamp BETWEEN date_trunc('DAY', NOW()) - interval '14' day AND date_trunc('DAY', NOW())
After cross checking both the query results I found that first condition is giving correct result.
Can someone please tell me the difference between both the conditions.
Thanks in advance

timestamp has a time component.
date_trunc(day, timestamp) removes the time component.
The second part of the comparison is different. The first version returns any time on the current day.
The second version only returns midnight on the current day.
Incidentally, I would recommend:
where timestamp >= current_date - interval '14 day' and
timestamp < current_date + interval '1 day'
This works, regardless of whether the timestamp column has a time component or not. And, it is friendly to the optimizer and index usage.

Related

How to get an accurate number of results when selecting records from a period of time

I have a problem very similar to this StackOverflow question in that I need a full seven days of records. My query looks something like this:
SELECT id, entry_timestamp
FROM entries
WHERE created_on >= TO_DATE('2023-01-25', 'YYYY-MM-DD') at time zone 'UTC' - interval '7 days'
ORDER BY entry_timestamp
In my table entry_timestamp is a "timestamp without timezone" column and created_on is a "date" column.
(I need the TO_DATE() instead of current_date because I need to be able to specify a particular date)
When I run that query I get results with entry_timestamp from the last six days.
If I change it to interval '8 days' I get ten days for some reason.
What am I missing that is causing such a broad miscalculation?

Need to pull records from previous full hour regardless of time the query runs

I want to pull records from the previous Full hour from when the query runs.
By this I mean regardless if it runs at 2:05 or 2:15 I will get records from 1:00:00 to 1:59:59.
Currently I get ORA-00907: missing right parenthesis error even though there are correct amount of parenthesis as far as I can tell. What am I doing wrong?
WHERE ((SS.NSAMPLE < SS.LSL OR SS.NSAMPLE > SS.USL) OR SS.FAILED = 'Y')
AND SD.DIMENSION_ID = SS.DIMENSION_ID
AND SUBDATE(STR_TO_DATE(DATE_FORMAT(NOW(), '%Y%m%d%H'), '%Y%m%d%H'), INTERVAL 1 HOUR) <= SS.SAMPLE_DATE AND SS.SAMPLE_DATE < STR_TO_DATE(DATE_FORMAT(NOW(), '%Y%m%d%H'), '%Y%m%d%H')
I also tried this and get the same missing right parenthesis error.
SUBDATE(SUBDATE(SUBDATE(SUBDATE(NOW(),
INTERVAL EXTRACT(MICROSECOND FROM NOW()) MICROSECOND),
INTERVAL EXTRACT(SECOND FROM NOW()) SECOND),
INTERVAL EXTRACT(MINUTE FROM NOW()) MINUTE),
INTERVAL 1 HOUR) <= SS.SAMPLE_DATE
AND SS.SAMPLE_DATE < SUBDATE(SUBDATE(SUBDATE(NOW(),
INTERVAL EXTRACT(MICROSECOND FROM NOW()) MICROSECOND),
INTERVAL EXTRACT(SECOND FROM NOW()) SECOND),
INTERVAL EXTRACT(MINUTE FROM NOW()) MINUTE)
You're using MySQL functions against an Oracle database. They are different database products, which both happen to be owned by Oracle Corp. (and have their documentation on docs.oracle.com), and the syntax varies. You might find the Oracle SQL Language Reference helpful.
To get data from the preceding hour in Oracle you can do:
AND SS.SAMPLE_DATE >= TRUNC(SYSDATE, 'HH') - INTERVAL '1' HOUR
AND SS.SAMPLE_DATE < TRUNC(SYSDATE, 'HH')
SYSDATE gives you the system time, e.g. 2022-12-21 17:30:37
TRUNC(SYSDATE, 'HH') gives you the system time truncated to the hour, e.g. 2022-12-21 17:00:00
TRUNC(SYSDATE, 'HH') - INTERVAL '1' HOUR gives you the system time truncated to the hour, with an hour subtracted, e.g. 2022-12-21 16:00:00
The two filter conditions then look for values greater than or equal to the previous hour, and less than (but not including) this hour, so effectively for that example system time:
AND SS.SAMPLE_DATE >= timestamp '2022-12-21 16:00:00'
AND SS.SAMPLE_DATE < timestamp '2022-12-21 17:00:00'
which covers all of the possible times in that hour-long period.
fiddle
The "ORA-00907: missing right parenthesis" error doesn't always mean you have the wrong number of parentheses. It means the parser got to a point where the next thing it expected to see was a right parenthesis, and it saw something else instead. It can have a variety of sometime non-obvious underlying problems.
In this case it's actually the interval syntax that's confusing it - if you change INTERVAL 1 HOUR to INTERVAL '1' HOUR to make it a valid Oracle interval literal then the error will change to "ORA-00904: "STR_TO_DATE": invalid identifier", which is easier to understand, as that's one of the MySQL functions that doesn't exist in Oracle.

trunc(add_months(sysdate,3),'Q')-1 equivalent expression in Postgres

can anybody convert this oracle expression trunc(add_months(sysdate,3),'Q')-1) to postgresql?
Basically this expression gives you the last day of the current quarter (provided that you remove the last closing parenthese, which otherwise is a syntax error).
In postgres, you could phrase this as:
date_trunc('quarter', current_date) + interval '3 months' - interval '1 day'
This generates a timestamp value, that you can cast if you want a date (this distinction does not exist in Oracle, where a date stores the time component as well).
The Postgres equivalent of your Oracle calculation can be seen below.
select date_trunc('quarter', current_date + interval '3 month') - interval '1 day'

Presto TIMESTAMP get data from 2 days ago without inputting year month date?

My goal is to have the query grab data from 2 days ago. I don't want to have to keep inputting the date like this:
WHERE usage_start_date
BETWEEN TIMESTAMP '2020-09-09 00:00:00.000' and TIMESTAMP '2020-09-09
23:59:59.999'
but instead something like:
usage_start_date = current_date - interval '2' day
the above works for my Athena Presto SQL query, but for some reason will not give all the data that ran in those 24 hours, instead giving about half the day. Is there a way to do a statement like this one to ensure it gives ALL data in that day?
WHERE current_date - interval '2' day AND
BETWEEN TIMESTAMP '00:00:00.000' and TIMESTAMP '23:59:59.999'
without inputting the year, month, day? It seems like TIMESTAMP needs the y/m/d but what about doing a LIKE so it picks up the hour, minute, second but no need to put the y/m/d?
To get a timestamp for the start of the day that was two days ago you can do
DATE_TRUNC('day', NOW() - INTERVAL '2' DAY)
e.g.
WHERE usage_start_date >= DATE_TRUNC('day', NOW() - INTERVAL '2' DAY)
AND usage_start_date < DATE_TRUNC('day', NOW() - INTERVAL '1' DAY)
You can use below query to achieve the task by fetching the hour and date from the usage_start_date
select * from table where hour(usage_start_date) between 0 and 23 and current_date - interval '2' day = date(usage_start_date)
I would suggest:
WHERE usage_start_date >= CURRENT_DATE - INTERVAL '2' DAY AND
usage_start_date < CURRENT_DATE - INTERVAL '1' DAY

How to run PostgreSQL Query every day with updated values?

New to SQL, but trying to learn/do a job for a friend. I have a query set up that returns the number of bookings for the day. Example snippet:
...
WHERE be.event IN ('instant_approve', 'approve') AND TO_CHAR(be.created_at, 'yyyy-mm-dd') BETWEEN '2017-06-26' AND '2017-06-26';
Now, this query is set up for just today. How can I set this up so that tomorrow the query is executed for '2017-06-27' and so on? Is this possible?
Built-in function now() gives you a timestamp of the beginning of your transaction (CURRENT_TIMESTAMP pseudo-constant is its "alias", a part of SQL standard, but I prefer using the function).
Another function, date_trunc() gives you a "truncated" timestamp and you can choose, how to truncate it. E.g., date_trunc('day', now()) will give you the date/time of beginning of the current day.
Also, you can add or subtract intervals easily, so here is an example that gives you the beginning of the current and the next days:
select
date_trunc('day', now()) cur_day_start,
date_trunc('day', now() + interval '1 day') as next_day_start
;
Also, I would not use to_char() or anything else on top of created_at column -- this will not allow Postgres planner use index on top of this field. If you do want to use to_char(), then consider adding a functional index over to_char(created_at, 'yyyy-mm-dd').
Here is how I would retrieve records generated at July 26, 2017:
where
created_at between '2017-06-26' and '2017-06-27'
(implicit type casting from text to timestamps here)
This is equivalent to
where
created_at >= '2017-06-26'
and created_at <= '2017-06-27'
-- so all timestamps generated for July 26, 2017 will match. And for such query Postgres will use a regular index created for created_at column (if any).
"Dynamic" version:
where
created_at between
date_trunc('day', now())
and date_trunc('day', now()) + interval '1 day'
Use current_date built-in function in the between condition and it will work only for today's bookings.
.........
WHERE be.event IN ('instant_approve', 'approve') AND TO_CHAR(be.created_at, 'yyyy-mm-dd') =current_date;