Between with Variables for prior months start and stop - oracle

I use the following WHERE with sysdate to get a between range.
WHERE TO_CHAR(mopstart, 'yyyy-mm-dd hh24:mi:ss') BETWEEN TO_CHAR(sysdate,'YYYY-MM-DD')||' 21:00:00' AND TO_CHAR(sysdate+1,'YYYY-MM-DD')||' 20:59:59'
My question is, how do I create a BETWEEN with variables for the date to return the prior months start and end date?

You would usually not use BETWEEN for this. As in real life you would not say "the time from beginning of last month till the end of last month", but just "last month", so you would do in SQL.
Knowing that a month is actually the year and the month:
where extract(year from mopstart) = extract(year from sysdate)
and extract(month from mopstart) = extract(month from sysdate) - 1
Or:
where to_char(mopstart,'yyyymm') = to_char(add_months(sysdate,-1),'yyyymm')

If I understand you well, that would be:
where ... between trunc(add_months(sysdate, -1), 'MON') and trunc(sysdate, 'MON') - 1
One more thing: don't use TO_CHAR to compare dates, just use dates and intervals.

Related

How to Enable button only selected Hours and Days oracle apex

I have created a button on Oracle Apex 21.1. I want to enable the button only under selected Hours and Days. I have applied "Server-side condition" with type "Rows returned".
Hours from Evening 04:00:00 PM Till Next Day Morning 08:00:00 AM.
Days From Monday to Saturday.
From this query, the button disappears after 08:00:00 PM Server / System Date. I have mentioned in the where clause that is button will disappear after 08:00:00 AM
SQL QUERY:
SELECT TO_CHAR(sysdate, 'HH:MI:SS PM'), REPLACE(TO_CHAR(sysdate, 'DAY'), ' ')
FROM dual
WHERE TO_CHAR(sysdate, 'HH:MI:SS PM') >= '04:00:00 PM'
AND TO_CHAR(sysdate, 'HH:MI:SS PM') <= '08:00:00 AM'
AND REPLACE(TO_CHAR(sysdate, 'DAY'), ' ') IN ('MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY',
'FRIDAY', 'SATURDAY')
;
For a question like this the easiest is to generate a list of dates and check if the where clause works ok. Generate a list of dates using CONNECT BY LEVEL < x. In my case I used a CASE statement instead of a where clause but the result is the same.
I changed a couple of things to make it less confusing:
change date format to HH24:MI:SS - that is just an alphanumeric string so there is no room for error when comparing strings. In your case, '03:01:00 AM > '02:01:00 PM' since your comparing strings. I doubt that is what you want. Better to use 24 hour format.
use FMDAY for the days: that trims the whitespace.
That being said, here is how to check a list of dates:
WITH some_dates (dt_str, dt) AS
(
SELECT TO_CHAR(SYSDATE + (LEVEL * 5)/24,'FMDAY DD-MON-YYYY HH24:MI'), SYSDATE + (LEVEL * 5)/24 FROM DUAL
CONNECT BY LEVEL < 40
)
SELECT DT_STR,
CASE WHEN
(TO_CHAR(dt,'HH24MI') >= '1600' OR TO_CHAR(dt,'HH24MI') <= '0800') AND
(TO_CHAR(dt,'FMDAY') NOT IN ('SATURDAY','SUNDAY'))
THEN 'Y' ELSE 'N' END
FROM some_dates;
This works. A 'Y' is shown for weekdays and Hours from Evening 04:00:00 PM Till Next Day Morning 08:00:00 AM. A 'N' for times that don't need to be shown.
So if we use that case statement in the where clause of statement in a server-side condition of type "rows returned" this gives:
SELECT 1 FROM DUAL WHERE
CASE WHEN
(TO_CHAR(sysdate,'HH24MI') >= '1600' OR TO_CHAR(sysdate,'HH24MI') <= '0800') AND
(TO_CHAR(sysdate,'FMDAY') NOT IN ('SATURDAY','SUNDAY'))
THEN 'Y' ELSE 'N' END = 'Y'
Adding on top of #koen-lostrie
I would suggest you compare dates with dates. What I would do is compare sysdate with the start and end of your business hours for today like:
select 1
from dual
where sysdate between to_date( to_char(sysdate, 'YYYY-MM-DD') || '0800', 'YYYY-MM-DDHH24MI')
and to_date( to_char(sysdate, 'YYYY-MM-DD') || '1600', 'YYYY-MM-DDHH24MI')
and to_char(sysdate,'FMDAY') not in ('SATURDAY','SUNDAY')
You may also want to add this to your process' condition to prevent someone from submitting something after 16:00 (in case they would have accessed the page at 15:59 with an enabled button)

how to get year and month into number oracle

i'm trying to get sysdate year and month into number or char.
I'd want something like this:
202107
or last month
202106
i tried this code:
select trunc(add_months(sysdate, -1), 'MM') from dual;
please help, thanks
Convert it to a string and then to a number:
SELECT TO_NUMBER(TO_CHAR(ADD_MONTHS(SYSDATE,-1), 'YYYYMM'))
FROM DUAL;
Or, you can use extract and wrap it in a sub-query so you do not need to repeat adding the months:
SELECT EXTRACT(YEAR FROM dt) * 100 + EXTRACT(MONTH FROM dt)
FROM (
SELECT ADD_MONTHS(SYSDATE, -1) AS dt
FROM DUAL
)
Like
SELECT EXTRACT(year from sysdate) * 100 + EXTRACT(month from sysdate)
If you want to scroll around, manipulate the date before you extract from it, rather than minusing after you extract (gets tricky to e.g. go back a month if the date is in jan)
--will work for jan 2021
SELECT EXTRACT(year from ADD_MONTHS(somedate, -1)) * 100 + EXTRACT(month from ADD_MONTHS(somedate, -1))
--won't work for jan 2021
SELECT EXTRACT(year from somedate) * 100 + (EXTRACT(month from somedate) - 1)
TRUNC is a device that "rounds" a date to a particular interval, such as "trimming the time off a datetime" or "making any day of the week back to the date that was the start of the week" - very useful for all sorts of stuff like "total sales by month - SUM(sale) GROUP BY TRUNC(saledate, 'mm')" but it keeps all the components of the date (the day, the hour, the minute etc) so it isn't what you want.

Calculating date range for Oracle

I'm automating an Oracle script, which needs to select data from the first day of last month, to the first day of this month (this report is run on the second day of every month). But, no matter what combination of LAST_DAY, TRUNC, TO_CHAR, TO_DATE, ADD_MONTHS, etc have worked.
Can someone help me figure out how to automate the calculation for:
WHERE date BETWEEN (first day of last month) AND (first day of this month)
You could use TRUNC:
WHERE date between trunc(trunc(sysdate,'MM')-1,'MM') and trunc(sysdate, 'MM');
db<>fiddle demo
select trunc(trunc(sysdate,'MM')-1,'MM') AS "first day of last month",
trunc(sysdate, 'MM') AS "first day of this month"
from dual;
from dual
This did the trick:
BETWEEN TO_CHAR(LAST_DAY(ADD_MONTHS(SYSDATE, -2)) +1, 'YYYY-MM-DD') AND TO_CHAR(LAST_DAY(ADD_MONTHS(SYSDATE, -1)) +1, 'YYYY-MM-DD')

Using "today" and "two days before" in date with Oracle

I have the following WHEREclause in a query:
SELECT ...
FROM ...
WHERE IMPORT_DATE between
to_date('2018-03-16 00:00:00', 'yyyy-mm-dd hh24:mi:ss') and
to_date('2018-03-16 23:59:59', 'yyyy-mm-dd hh24:mi:ss')
And I would like to write two new queries:
One with this same clause but using "today" instead of "2018-03-16".
Another with the same clause but using "the day before yesterday" (today - 2) instead of "2018-03-16".
How can I do this in Oracle?
As Oracle has no real DATE data type and always includes a time, it's usually better to not use between for conditions like that, but to use >= together with < compared to midnight the next day.
To find the rows from "today" use:
SELECT ...
FROM ...
WHERE import_date >= trunc(sysdate)
AND import_date < trunc(sysdate) + 1;
or:
SELECT ...
FROM ...
WHERE import_date >= trunc(sysdate) - 2
AND import_date < (trunc(sysdate) - 2) + 1;
The parentheses aren't really required in the second expression, they are just there to document that it's the same expression as the first one.
select trunc(sysdate) from dual;
Returns today's date without any time
select trunc(sysdate) - interval '2' day from dual;
Returns the day 2 days before today without time.
You can also use month, hour, year etc instead of day.

How to get data from first day of the month until yesterday

does anyone know the query to get data from first day of the month until yesterday? I Try using query below but the problem is when today is the first day of the month, so the value become between 20170201 and 20170131
select * from a where to_char(DATE,'yyyymmdd') BETWEEN to_char(sysdate,'yyyymm')||'01' and to_char(sysdate-1,'yyyymmdd')
Ex: if today is 01-02-2017 i want to select the data from 01-01-2017 until 31-01-2017, but if today is 13-02-2017 i want to select the data from 01-02-2017 until 12-02-2017, thank's before
This question has been updated with your new logic. The query below will retain records under the following conditions:
someDate falls between the first day and yesterday of the current month, or
someDate, when today is the first of the month, falls anywhere in the previous month
SELECT *
FROM yourTable
WHERE someDate BETWEEN CASE WHEN EXTRACT(DAY FROM SYSDATE) = 1
THEN TRUNC(SYSDATE-1, 'MONTH')
ELSE TRUNC(SYSDATE, 'MONTH') END AND
CASE WHEN EXTRACT(DAY FROM SYSDATE) = 1
THEN TRUNC(SYSDATE, 'MONTH') - 1
ELSE TRUNC(SYSDATE - 1) END
This query assumes that you have a DATE column called someDate.

Resources