Using Case Statement in Where Clause ___ Using date ranges with BETWEEN - sql

I am trying to filter a date to a specific range depending on whether or not we have passed the first weekday of the current month.
Oracle seems to not like that I am using BETWEEN.
WHEN
TO_DATE(myDate,'YYYYMMDD')=CASE WHEN TO_DATE(SYSDATE-1) - TO_DATE(last_day(add_months(sysdate, -1))+6)>0
THEN
TO_DATE(last_day(add_months(sysdate, -1))+1, 'YYYYMMDD') --AND to_date(TRUNC(SYSDATE) - 1, 'YYYYMMDD')
Else
TO_DATE(last_day(add_months(sysdate, -2))+1, 'YYYYMMDD') --AND to_date(TRUNC(SYSDATE) - 1, 'YYYYMMDD')
END
Please let me know how to correct this.

If you want dates that are equal to or after the first monday of the current month, you can do:
to_date(my_date, 'YYYYMMDD') >= next_day(trunc(sysdate, 'MM') - 1, 'MONDAY')
trunc(sysdate, 'MM') - 1 gives you the last day of the previous month. Then next_day(..., 'MONDAY') gives you the following Monday.
You can change the day name according to what your definition of a week day is. Also, it is worth noting that the day name (the second argument to next_day() must be provided in the language of your session.

Related

Identify the day and get the previous date in Oracle SQL

I have below query which gives current date. I want to return the value as String for this reason i used TO_CHAR.
select NVL(TO_CHAR(sysdate,'DD.MM.YYYY'),0) from dual
But i need to identify Day and based on this it should return the previous Date.
For example when the query runs on every Monday it should return the date from last Friday. When the query runs from Tuesday till Friday it should return the date from previous day.
For example when the query runs today it should return the date from last Friday i.e 18.02.2022. When the query runs tommorow it should return the date from Today 21.02.2022.
I want to avoid dates from every Saturday and Sunday. Can we do this in one query ?
If you want to do it so that the query will work in any language and/or territory then you can compare the date to the start of the ISO week:
SELECT TO_CHAR(SYSDATE, 'DD.MM.YYYY') AS today,
CASE TRUNC(SYSDATE) - TRUNC(SYSDATE, 'IW')
WHEN 0 THEN TO_CHAR(SYSDATE - 3, 'DD.MM.YYYY') -- Monday
WHEN 6 THEN TO_CHAR(SYSDATE - 2, 'DD.MM.YYYY') -- Sunday
ELSE TO_CHAR(SYSDATE - 1, 'DD.MM.YYYY') -- Any other day
END AS previous_weekday
FROM DUAL;
db<>fiddle here
As a slight variation on MTO's answer, just to perhaps make it clearer to a future maintainer, you could use day names or abbreviations instead - but would need to specify the date language (which maybe assumes the hypothetical future maintainer uses, or at least understands, that language):
select to_char(sysdate
- case to_char(sysdate, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH')
when 'MON' then 3
when 'SUN' then 2
else 1
end, 'DD.MM.YYYY') as result
from dual
RESULT
----------
18.02.2022
db<>fiddle, including what you see for a range of 14 days, not just today.

SQL date with fixed day and month but relative year

I've created a report in BusinessObjects WEBI but I would like to customize the underlying SQL so that the year in the date range changes based on when the query is run, leaving the day and month unchanged
This example ...
WHERE
ACT_ENDDT BETWEEN '01-10-2019 00:00:00' AND '30-09-2020 00:00:00'
... is desirable if I ran the query now (current year -1 AND current year, respectively) but if I were to run this query in 2021 I want those years to change to 2020 and 2021, respectively, keeping the day and months the same (10/1 and 9/30).
I searched through a few resources like sqltutorial and w3schools but I'm barely a novice at this and can't wrap my head around how to make it work. I also tried the solution provided here in thread 28707795 as such:
ACT_ENDDT BETWEEN DATEFROMPARTS(YEAR(getdate())-1,10,1) AND DATEFROMPARTS(YEAR(getdate()),9,30)
... but end up with a message that DATEFROMPARTS is an invalid identifier.
Is there a way to hard code part of the date and have a modifier attached to it for just the year, e.g. ... BETWEEN '01-10-'&[*currentyear* - 1] ...?
Thanks.
You can use date artithmetics like this:
where act_enddt between trunc(sysdate, 'year') - interval '3' month
and trunc(sysdate, 'year') + interval '9' month - interval '1' day
I wonder whether a half-open interval may also be helpful:
where act_enddt >= trunc(sysdate, 'year') - interval '3' month
and act_enddt < trunc(sysdate, 'year') + interval '9' month
The difference between the two expressions is that the latter allows dates between October 30th at 00:00 and the end of that day. If your dates have no time component, this does not make a difference (and the second expression is a bit neater).
You can use extract() to extract the year portion of sysdate, do arithmetic on it, like subtracting one, concatenate the month and day portion to complete it to be a date representation and convert this string to a date with to_date().
That's
to_date(extract(YEAR FROM sysdate) - 1 || '-10-01', 'YYYY-MM-DD')
for your lower and
to_date(extract(YEAR FROM sysdate) || '-09-30', 'YYYY-MM-DD')
for your upper boundary.

Maximo UI SQL Select Month

I am trying to write a query using SQL in the Maximo 7.5 UI advanced search function which will return data from the month before the month in which the query was run. I want to save this query and make it available to users who will run the query without editing it. For example, if a user ran the saved query on 1/25/2019, the query would return all records for which the date was any day in December 2018. I have previously used "where actfinish >= sysdate-30" but the length on months varies and I cannot rely on the users (who do not write SQL) to always run the query on the first day of each month, so I need the query to filter by the previous month. The field I am filtering on is a DATE field, but in the DB it looks like DD-MMM-YY.
Your current where actfinish >= sysdate-30 will return data from the current month, as well as the issues you mentioned.
You can do something like:
where actfinish >= add_months(trunc(sysdate, 'MM'), -1)
and actfinish < trunc(sysdate, 'MM')
The trunc(sysdate, 'MM') gives you midnight on the first day of the current month. The first clausesubtracts a month from that, so gives you midnight on the first day of the previous month; the second clause prevent any record from this month being included.
You can check what those evaluate to by querying the terms outside your real query:
alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS';
select sysdate,
add_months(trunc(sysdate, 'MM'), -1) as month_from,
trunc(sysdate, 'MM') as month_to
from dual;
SYSDATE MONTH_FROM MONTH_TO
------------------- ------------------- -------------------
2019-01-25 12:59:53 2018-12-01 00:00:00 2019-01-01 00:00:00
The alter session is just to make the client format the results in a particular way, instead of explicitly doing to_char().
When you said "in the DB it looks like DD-MMM-YY", it doesn't actually look like that in the database; when you query the date values your client is formatting the dates like that, so your NLS_DATE_FORMAT is probably set to the still-default DD-MON-RR model. (And it's MON in Oracle, not MMM - see the format model elements in the docs.)
Your solution will depend on the type of database that is being used.
For SQL Server, we have used logic along the following lines:
actfinish between dateadd(day,1,eomonth(dateadd(month,-2,getdate()))) and eomonth(dateadd(month,-1,getdate()))
(identify the last day of the previous month and the last day of the month before that + 1 day)
For Oracle, the equivalent would be:
trunc(actfinish,'MONTH') = add_months(trunc(sysdate,'MONTH'),-1)
(identify the year and month associated with last month and compare that against the target date components - trunc month function removes the time and day of month components so making comparisons easier)
I have previously used "where actfinish >= sysdate-30" but the length
on months varies.
By "length of month", do you mean the number of days for each month (e.g. 30, 31, 28, 29) or just a formatting issue with the month? If I understood your question correctly, you can convert the date to character then convert that to date and Oracle will take care of the change in the number of days. For example, something like:
where to_date(to_char(actfinish, 'mm/dd/yyyy')) >= to_date(to_char(sysdate, 'mm/dd/yyyy'))-30
or
where to_date(to_char(actfinish), 'mm/dd/yyyy') >= to_date(to_char(sysdate), 'mm/dd/yyyy')-30
I don't have Maximo installed on my personal laptop so you can try the two I listed above.

PostgreSQL convert month string to start and end dates of month

Is it possible to convert e.g. string "201701" to dates '2017-01-01' and '2017-01-31' in PostgreSQL?
So for:
"201701" get '2017-01-01' and '2017-01-31'
"201702" get '2017-02-01' and '2017-02-28'
"201703" get '2017-03-01' and '2017-02-31'
etc
You may use the TO_DATE function, and append the day component using string concatenation, something like this:
SELECT
TO_DATE('201702' || '01', 'YYYYMMDD') AS first,
(TO_DATE('201702' || '01', 'YYYYMMDD') + INTERVAL '1 month') -
INTERVAL '1 day' AS last;
The above trick just adds 01 to form the first of the month. For the last day of the same month, it first adds one month to the first, to get the first of the next month, then rolls back one day to get the last of the current month.
Demo
The above answer by Tim Biegeleisen works, but here's an alternative.
The to_date() function converts a string literal to a date value.
sample usage is : to_date(text,format);
SELECT to_date('201701','YYYYMMDD');
(EDITED)
You can also use date_trunc which is a part of PostgreSQL. It does the same as the above one.
select date_trunc('month', current_date) , date_trunc('month', CURRENT_DATE) + interval '1 month - 1 day';
Code Example Live Demo

In Oracle SQL, how to get the time for only this current week?

I have a query , where I want to obtain some data for different time durations (this month, this week, etc).
For the "this week" column, I want it to get all the data from the most recent Monday until now. How would I do this?
I have the following SQL so far :
WHERE prla.CREATION_DATE >= SYSDATE - ?
trunc(sysdate, 'iw') is what you're after. IW is the format mask used for Monday of the week the specified date is in (as Monday is the ISO standard for the start of the week). E.g.:
with dates as (select trunc(sysdate, 'mm') - 10 + level dt
from dual
connect by level <= 40)
select dt
from dates
where dt >= trunc(sysdate, 'iw')
and dt <= sysdate; -- only needed if the dates in the column could be beyond now.
Yeah that will do: But it is better to use sysdate-8. Because if the current day is same as your searching day, it will return the current date. For Eg.
select next_day(sysdate-7,'WED') from dual;
OUTPUT
19-AUG-15
Whereas the below one will give you the last week
select next_day(sysdate-8,'WED') from dual;
OUTPUT
12-AUG-15
You should truncate the current date.
TRUNC(SYSDATE, 'DAY')
This should give you the first day of the week, which is Monday in lot of countries.
If it's giving you the previous Sunday instead you should do this.
TRUNC(SYSDATE, 'DAY')+1
I found out to do this now:
select next_day (sysdate-7, 'MONDAY') Last_Monday from dual;
So in my case, we can remove the SYSDATE subtraction and it is simply :
prla.CREATION_DATE >= next_day (sysdate-7, 'MONDAY')
source