I would like to convert the payment day field from AUTO_TABLE into a day of the month. The payment day is stored in string format and the first nine days are stored as single character. I want to append a '0' string before the payment day for day 1-9 and convert the resulting string into 'DD'. The query worked for two months, but Oracle throws an error stating "invalid Month" when I attempt to convert the string into a date. How can I convert the payment day into two character decimals and proceed to concatenate day with the current month and year? Thanks for your help.
Select case when Payment_Day <> to_char(sysdate, 'dd')
then Payment_Day
end as Payment_day,
Payment_Day2,
trunc(sysdate) - 8 as DateEdit2,
trunc(sysdate) - 15 DateEdit1
From(
Select case when Payment_Day2 > trunc(sysdate)
then Payment_day2 - 31
else Payment_Day2 end as Payment_Day2,
Payment_Day, theSysdate as theSysdate
From(
Select distinct to_date(Payment_Day2, 'MM/DD/YYYY') as Payment_Day2,
Payment_Day, theSysdate
From(
Select thePIDM,
to_char(DateEdit, 'MM') || '/' || to_char(Payment_Day, '00') || '/' || to_char(sysdate, 'YYYY') as Payment_Day2,
to_char(Payment_Day) as Payment_Day, Trunc(theSysdate) theSysdate
From (
Select distinct PIDM as thePIDM,
to_char(Payment_Day) as Payment_Day,
trunc(sysdate) as DateEdit,
to_char(sysdate, 'DD') as theSysdate
from AUTO_TABLE
Group by PIDM, to_char(Payment_Day)
)
)
Order by Payment_Day2
)
Order by Payment_Day2
)
The query worked for two months. Yes you were lucky the run it in July and August, both having 31 days.
The problem is in the line
to_char(DateEdit, 'MM') || '/' || to_char(Payment_Day, '00') || '/' || to_char(sysdate, 'YYYY') as Payment_Day2,
which mix the payment_day with the current month (from sysdate). This leads to invalid dates such as 09/ 31/2015.
The remedy is in reducing the payment day to the last day of the current month
-- instead of
-- to_char(Payment_Day) as Payment_Day,
-- limit the payment day to the last day of the current month
to_char(least(to_number(Payment_Day),CAST(to_char(LAST_DAY(sysdate),'dd') AS INT))) as Payment_Day,
Related
I have a table called birthdays with 2 columns name and date.
Name is string value, date is date (Looks like this: 1989-07-28 00:00:00)
How can i get closest birthday, according to day i am checking, for example NOW()
Using PostgreSQL
The question is determining if the year is this year or next year:
select (case when to_char(dob, 'MM-DD') >= to_char(now(), 'MM-DD')
then to_date(to_char(current_date, 'YYYY') || '-' || to_char(dob, 'MM-DD'), 'YYYY-MM-DD')
else to_date(to_char(current_date, 'YYYY') || '-' || to_char(dob, 'MM-DD'), 'YYYY-MM-DD') + interval '1 year'
end)
from (values ('1989-07-28'::date)) v(dob);
Assuming you are searching for forward-looking birthdays, the query below takes the minimum difference in days starting from current date
Select "Date" - Current_Date as diff,
"Date" as Dob,
Name
from birthdays
Where ("Date"- Current_Date) > 0
Order by 1 asc
limit 1;
First off in Postgres if your column is defined as DATE then it does not appear as "1989-07-28 00:00:00". Dates in Postgres do not have time components, so no "00:00:00" (unless you have done something with datestyle. But that is actually immaterial here.
Postgres dates can be directly subtracted to get the days number of between them, with the result either positive or negative depending upon which date occurs first. To
get the "closest" to a specific data just take the absolute value.
with birthdays (name, bday) as
( values ('George', date '2020-10-18')
, ('Gloryann', date '2020-11-02')
, ('Phyllis', date '2020-10-09')
, ('Sam', date '2020-06-18')
)
select name, bday birthday
from birthdays
order by abs(current_date-bday)
limit 1;
Caution: Do not use date as an object name. Date is both a Postres and SQL standard reserved word. While using it may be permitted currently Postges would be within their right to enforce the predefined meaning at anytime, potentially causing major issues for your app. Play it safe Do Not use reserved words as object names.
Thanks guys, it works perfect this way:
select name, date, (case when to_char(date, 'MM-DD') >= to_char(now(), 'MM-DD') then
to_date(to_char(current_date, 'YYYY') || '-' || to_char(date, 'MM-DD'), 'YYYY-MM-DD')
else to_date(to_char(current_date, 'YYYY') || '-' || to_char(date, 'MM-DD'), 'YYYY-MM-DD') + interval '1 year' end)
from birthdays order by 3
I am trying to check a condition if given date is in current financial year i.e april to march. but not getting any idea how to do
code
select nvl(Count(1), 0)+1 from ASET where IPE='O' and irt in (SELECT EXTRACT (YEAR FROM ADD_MONTHS (SYSDATE, -3))
|| '-'
|| EXTRACT (YEAR FROM ADD_MONTHS (SYSDATE, 9))
FROM DUAL)
irt is date 01-09-2020.
I think the simplest approach is to offset the date column and sysdate by 3 months, and compare the year part:
where to_char(add_months(irt, -3), 'yyyy') = to_char(add_months(sysdate, -3), 'yyyy')
I am told to create a calendar-like list of dates based on existing records and to tell if a record exists on that date.
To have a sample scenario, take these records from a sample table: TIME_LOG(ID, PUNCH_TIME).
1 1/1/2018 8:00:00
2 1/1/2018 12:12:00
...
n 2/14/2020 8:00:00
In this example, what I need to do is to:
Get all the months present on the TIME_LOG, which are January 2018 and February 2020.
List all dates inside those two months, which are January 1 - 31, 2018 plus February 1 - 29, 2020. And then set it as column DATE_TOKEN of the result set.
Set 'Record found' or 'No records found' whether the value from DATE_TOKEN column exists from TIME_LOG. Make that as column IS_FOUND of the result set.
To retrieve that result set, this is my preliminary query:
SELECT a.date_token,
NVL2 (b.date_token, 'Record found.',
'No records found.') AS is_found
FROM (SELECT TO_DATE (a.MONTH || '/' || b.DAY || '/' || a.YEAR,
'MM/DD/YYYY'
) AS date_token
FROM (SELECT TO_CHAR (EXTRACT (MONTH FROM a.punch_time)
) AS MONTH,
TO_CHAR (EXTRACT (YEAR FROM a.punch_time)) AS YEAR
FROM vw_each_punch a
GROUP BY TO_CHAR (EXTRACT (MONTH FROM a.punch_time)),
TO_CHAR (EXTRACT (YEAR FROM a.punch_time))) a
JOIN
(SELECT TO_CHAR (ROWNUM) AS DAY
FROM DUAL
CONNECT BY ROWNUM <= 31) b
-- I placed this condition to eliminate dates such as February 31, etc.
-- and it works unless I uncomment the WHERE clause below.
ON b.DAY <=
EXTRACT (DAY FROM LAST_DAY (TO_DATE ( a.MONTH
|| '/1/'
|| a.YEAR,
'MM/DD/YYYY'
)
)
)
) a
LEFT JOIN
(SELECT TRUNC (a.punch_time) AS date_token
FROM vw_each_punch a
GROUP BY TRUNC (a.punch_time)) b ON b.date_token = a.date_token
-- WHERE TRUNC (a.date_token, 'MONTH') = '1-FEB-2020'
ORDER BY 1, 2
This works fine and retrieves 60 rows on the resultset, similar to this (DATE_TOKEN, IS_FOUND):
1/1/2018 Record found.
1/2/2018 No records found.
1/3/2018 No records found.
...
2/13/2018 No records found.
2/14/2018 Record found.
2/15/2018 No records found.
...
until I needed to filter the resultset with certain months. When I try to uncomment the WHERE clause on my query to show only the dates on February 2020, it throws me an error:
ORA-01839: date not valid for month specified
The resultset loads completely without any errors as long as there are no WHERE clause, shown by the previous resultset with 60 rows. I suspect the error originates from the fact that February 2020 is less than 31 days, but that has been removed by b.DAY <= EXTRACT (DAY FROM LAST_DAY (TO_DATE (a.MONTH || '/1/' || a.YEAR, 'MM/DD/YYYY'))) condition. Also, I changed the condition from February 2020 to January 2018 but it still doesn't work.
Is there any way I can use the WHERE clause without it throwing an ORA-01839 error?
Here is a running SQL sample using subquery factoring if you need to run it ASAP:
WITH time_log_temp (id, punch_time)
AS (SELECT 1,
To_date('2018-1-1 8:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM')
FROM dual
UNION ALL
SELECT 2,
To_date('2018-1-1 12:12:00 AM', 'YYYY-MM-DD HH:MI:SS AM')
FROM dual
UNION ALL
SELECT 2,
To_date('2020-2-14 8:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM')
FROM dual),
inter
AS (SELECT a.date_token,
Nvl2 (b.date_token, 'Record found.', 'No records found.') AS
is_found
FROM (SELECT To_date (a.month
|| '/'
|| b.day
|| '/'
|| a.year, 'MM/DD/YYYY') AS date_token
FROM (SELECT To_char (Extract (month FROM a.punch_time)) AS
MONTH,
To_char (Extract (year FROM a.punch_time)) AS
YEAR
FROM time_log_temp a
GROUP BY To_char (Extract (month FROM a.punch_time)),
To_char (Extract (year FROM a.punch_time))) a
join (SELECT To_char (ROWNUM) AS DAY
FROM dual
CONNECT BY ROWNUM <= 31) b
-- I placed this condition to eliminate dates such as February 31, etc.
-- and it works unless I uncomment the WHERE clause below.
ON b.day <= Extract (day FROM Last_day (
To_date (a.month
|| '/1/'
|| a.year,
'MM/DD/YYYY')))) a
left join (SELECT Trunc (a.punch_time) AS date_token
FROM time_log_temp a
GROUP BY Trunc (a.punch_time)) b
ON b.date_token = a.date_token
ORDER BY 1,
2)
SELECT *
FROM inter
-- WHERE Trunc(date_token, 'MONTH') = '1-JAN-2018'
I'm not sure how you're getting exactly that error from the filters you've shown, but fundamentally the problem is that you're comparing your (truncated) date with a string, which has to be implicitly converted to a date for the comparison. That relies on your NLS settings, specifically NLS_DATE_FORMAT; and that clearly don't match the string format.
You should change the filter to compare against a date instead:
WHERE Trunc(date_token, 'MONTH') = to_date('1-FEB-2020', 'DD-MON-YYYY')
... which is still relying on your NLS_DATE_LANGUAGE setting for the month name, or slightly better:
WHERE Trunc(date_token, 'MONTH') = to_date('01-02-2020', 'DD-MM-YYYY')
or better still, shorter and unambiguous, use an ANSI date literal:
WHERE Trunc(date_token, 'MONTH') = DATE'2020-02-01'
Another approach that avoids having to truncate the date column (which may prevent an index being used in your real query) is to use a date range instead:
WHERE date_token >= DATE '2020-02-01' AND date_token < DATE'2020-03-01'
How to get first date and last date of month in oracle by giving input parameter as month.
For eg. if i give input month as 'Jan' and Year as '2016' it should give first date and last date of the month.
You can use TRUNC for that:
First day:
TRUNC(your_date, 'MM')
Last day:
ADD_MONTHS(TRUNC(your_date, 'MM'), 1) - 1
You basically TRUNC the month to its first day, add one month to get the first day of the next month, and then go back a day.
If you do not have a date in the month but only the month and the year you can simply use the first of each month to construct a date:
TO_DATE('1.' || your_month || '.' || your_year, 'DD.MM.YYYY')
ADD_MONTHS(TO_DATE('1.' || your_month || '.' || your_year, 'DD.MM.YYYY'), 1) - 1
You can use the TRUNC and LAST_DAY functions for this purpose.
select TRUNC(d,'MM'), LAST_DAY(d)
from (select to_date('01-2016','MM-YYYY') as d from dual);
01-JAN-2016 00:00:00 31-JAN-2016 00:00:00
Requirement is input date should produce first day of the month.
Condtions are:
If the date entered is between 16-nov to 30-nov, then the first day will be 16-nov.
if the date entered is between 1-nov to 15-nov , then the first day will be 01-nov.
for all other month it should return 01st day of corresponding month.
Building on Tim Biegeleisen's solution, simplifying it and avoid the date-to-text-to-date conversions. Note the use of TRUNC to get the first date of the period.
SELECT
CASE
WHEN EXTRACT(MONTH FROM DATE_COL) = 11 AND EXTRACT(DAY FROM DATE_COL) >= 16
THEN TRUNC(DATE_COL, 'MONTH') + 15
ELSE TRUNC(DATE_COL, 'MONTH')
END AS FIRST_OF_MONTH
FROM T1
I used a lengthy CASE expression to handle this, containing the logic for the three cases you mentioned in your question.
SELECT CASE WHEN EXTRACT(month FROM date) = 11 AND
EXTRACT(day FROM date) >= 16
THEN TO_DATE(EXTRACT(year FROM date) || '-11-16', 'yyyy-mm-dd')
ELSE TO_DATE(EXTRACT(year FROM date) || '-' || EXTRACT(month FROM date) ||
'-01', 'yyyy-mm-dd')
END AS newDate
FROM yourTable