i am new to oracle. i need to compare date column with the current date in oracle 11g
for an example my table is
srno dob
1 1992-04-01
2 1988-04-01
3 1995-04-01
so i have to compre dob with the sysdate. if it is matched then must show the data.
i have tried this query to get result.
select dob
from xyz
where extract(month from dob)=extract(month from sysdate)
and extract(day from dob)=extract(day from sysdate);
but it is not working. please tell me where am i going wrong.
thanks.
select ...
where to_char(dob,'MMDD')=to_char(sysdate,'MMDD')
There are easier ways to compare two dates in Oracle. Try the solution below:
select random_date_1, random_date_2,
-- when you have to match the complete date
/* use to_char(random_date_1,'Dd-Mon-Yy hh24.mi.ss')
when comparing date time */
/* use to_char(random_date_1,'Dd-Mon-Yy hh24')
when only checking the date and hour (this is actually useful in a scenarios */
case when trunc(random_date_1) = trunc(random_date_2)
then 'Match' else 'No Match' end as method_1,
case when to_char(random_date_1,'Dd-Mon-Yy') = to_char(random_date_2,'Dd-Mon-Yy')
then 'Match' else 'No Match' end as method_2,
-- when you have to match only month
case when trunc(random_date_1,'Mon') = trunc(random_date_2,'Mon')
then 'Match' else 'No Match' end as method_3,
case when to_char(random_date_1,'Mon') = to_char(random_date_2,'Mon')
then 'Match' else 'No Match' end as method_4
from
(select to_date(round (dbms_random.value (24, 31))
|| '-'
|| round (dbms_random.value (01, 01))
|| '-'
|| round (dbms_random.value (2015, 2015)),
'DD-MM-YYYY') + level - 1 random_date_1,
to_date(round (dbms_random.value (27, 31))
|| '-'
|| round (dbms_random.value (01, 01))
|| '-'
|| round (dbms_random.value (2015, 2015)),
'DD-MM-YYYY') + level - 1 random_date_2 from dual
connect by level <= 10);
Try this
SELECT DOB
FROM XYZ
WHERE TRUNC (DOB) = TRUNC (SYSDATE)
As said above use to_char if you need to do a conversion, and look at the different format masks available. If your dob datatype is a date then you can compare directly with the SYSDATE value. As above getting just MMDD will give you just the month (04) and the day (01) as a char string for comparison.
I've just tried out the example you gave in your question and can't see what is wrong with using extract, as you have shown:
select dob
from xyz
where extract(month from dob)=extract(month from sysdate)
and extract(day from dob)=extract(day from sysdate);
Or am I misunderstanding something? You say that the code isn't working but I can't see what you mean.
I prefer to use extract rather than to_char in this sort of situation as I feel that it more clearly represents what I want. I don't want a character representation of the date, I just want to compare the month and the day.
Here is a SQLFiddle with an example: http://sqlfiddle.com/#!4/c545c/2
What is the error you are getting?
In your DB is dob field defined as DATE or varchar2?
In case your DB field is varchar2, then you may have to use,
SELECT * FROM XYZ
WHERE TRUNC ( TO_DATE(DOB, 'YYYY-MM-DD') ) = TRUNC (SYSDATE);
Related
I am passing two parameters - Month and year
Month can be 01/2022, 02/2022, 03/2022 etc
Year can be 2022, 2021,2020
Year is mandatory
I have a condition in the query that compares these dates -
SELECT Max(acrl2.accrual_period)
FROM anc_per_accrual_entries acrl2
WHERE person_id = 123
AND acrl2.plan_id = 1678
acrl2.accrual_period
and to_char(acrl2.accrual_period,'yyyy') = NVL(:p_year,to_char(acrl2.accrual_period,'yyyy'))
AND acrl2.accrual_period <= Nvl((
CASE
WHEN :p_month IS NOT NULL
THEN To_date(To_char(Last_day(To_date(:p_month, 'yyyy/mm')), 'yyyymmdd'), 'yyyymmdd')
WHEN :p_year IS NOT NULL
THEN To_date(:p_year || '1231', 'yyyymmdd')
END) ,sysdate)
When i pass one month - say 01/2022 - I am getting the correct output. or when i am passing just 2021, I am getting an output.
The issue is when i select multiple months 01/2022, 02/2022 or 2021,2022.
I know i can use in clause. But I am not being able to use it with <=
Not sure about what you expect when the conditions are met, but herre is what you can do with the conditions themselves. Case works in a way that it will accept the first WHEN condition satisfied end exits. So, if first when cond is true the second is not considered at all. I split the two (month, year) to be tested both. Also there is INSTR function which tests p_month and p_year.
SELECT
Max(acrl2.accrual_period)
FROM
anc_per_accrual_entries acrl2
WHERE
person_id = 123 And
acrl2.plan_id = 1678 And
TRUNC(acrl2.accrual_period, 'dd') <= (CASE
WHEN Instr(:p_month, To_Char(acrl2.accrual_period, 'mm/yyyy')) > 0
THEN To_Date(To_char(Last_day(acrl2.accrual_period), 'yyyymmdd'), 'yyyymmdd')
END) And
TRUNC(acrl2.accrual_period, 'dd') <= (CASE
WHEN Instr(:p_year, To_Char(acrl2.accrual_period, 'yyyy')) > 0
THEN To_Date(To_char(acrl2.accrual_period, 'yyyy') || '1231', 'yyyymmdd')
END)
I have two parameters MONTH and YEAR, how get all date?
Eg. YEAR = 2021, MONTH = 8
Date
------
01.08.2021
02.08.2021
.....
31.08.2021
I'm a fan of recursive CTEs, because they are standard SQL. In Oracle, you can use one like this:
with cte(dte) as (
select to_date('2020' || '8', 'YYYYMM') -- the two parameters are '2020' and '8'
from dual
union all
select dte + interval '1' day
from cte
where dte < last_day(dte)
)
select *
from cte;
Here is a db<>fiddle.
select dt + level - 1 as date_
from (select to_date(to_char(:year , 'fm0000') ||
to_char(:month, 'fm00'), 'yyyymm') as dt from dual)
connect by level <= add_months(dt, 1) - dt
;
This is almost the same as MT0's answer, with a few minor differences and one that is not entirely minor.
The to_date function assumes a default of first day of the month, so it is not necessary to explicitly concatenate '01' to the year and month (although perhaps doing so makes the code easier to read for beginner programmers). In my opinion, that's just a matter of taste.
I separated the computation of the first day of the month into a subquery. No worries, the optimizer will merge it into the outer query, so there is no efficiency cost - but the code will be easier to maintain.
The non-trivial difference is in the connect by clause. Even though mathematically the formula is equivalent to
dt + level - 1 < add_months(dt, 1)
or, better (still equivalent!)
dt + level <= add_months(dt, 1)
in terms of processing they are not equivalent. If written in the form above (previous line of code), for each value of level, the runtime will perform a date arithmetic calculation followed by a date comparison.
On the other hand, by solving the inequality for level (as I did in my query), the date calculation is performed just once (rather than once for every row), and the comparison is simply level <= some calculated number.
Perhaps in this problem "efficiency" plays no role, but as a matter of good coding, we should "solve for level" whenever possible, for the reason I just gave.
Assuming you pass in the bind variables :year and :month, then you can use a hierarchical query:
SELECT TO_DATE(
TO_CHAR(:year, 'FM0000') || TO_CHAR(:month, 'FM00') || '01',
'YYYYMMDD'
) + LEVEL - 1 AS "Date"
FROM DUAL
CONNECT BY
TO_DATE(
TO_CHAR(:year, 'FM0000') || TO_CHAR(:month, 'FM00') || '01',
'YYYYMMDD'
) + LEVEL - 1
<
ADD_MONTHS(
TO_DATE(
TO_CHAR(:year, 'FM0000') || TO_CHAR(:month, 'FM00') || '01',
'YYYYMMDD'
),
1
)
sqlfiddle here
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
SELECT DISTINCT
TO_CHAR(CREATION_DATE,'MONTH') creation_month
FROM
AP_INVOICES_ALL;
This query retrieves the month properly. But if I pass the month in where clause it doesn't retrieve data.
SELECT DISTCINT
TO_CHAR(CREATION_DATE, 'MONTH') CREATION_MONTH
FROM
AP_INVOICES_ALL
WHERE
TO_CHAR(CREATION_DATE, 'MONTH') = 'MARCH';
Please assist. I need to pass month as parameter in one report.
This is a known issue with 'MONTH' formats. The string is padded with characters.
Instead, use 'MON'. Check this out:
select to_char(sysdate, 'MONTH'),
(case when to_char(sysdate, 'MONTH')= 'APRIL' then 1 else 0 end),
to_char(sysdate, 'MON'),
(case when to_char(sysdate, 'MON')= 'APR' then 1 else 0 end)
from dual;
The first case expression returns 0 -- no match. The second returns 1, indicating that they do match.
I think passing in just the month, without the year, is not a good idea. And you will be far better off treating dates as dates, comparing them to dates, etc. Might I suggest something like the following?
SELECT TO_CHAR(creation_date, 'MONTH') AS creation_month
FROM ap_invoices_all
WHERE TRUNC(creation_date, 'MONTH') = DATE'2018-03-01';
TRUNC()ing the date to the month will return a value of type DATE of the first of the month at midnight. You can then compare using regular Oracle DATE values or ANSI DATE literals as above.
Hope this helps.
Below shows a executable statement:
Successful attempt:
INSERT INTO Personnel_Assignment (DATE, testno, Hours)
SELECT '21-OCT-2011', '12345',
CASE
WHEN Extract(day From(S.ENDTIME-S.STARTTIME) ) >= 1
THEN (Extract(Day From(S.ENDTIME-S.STARTTIME) ) * 24
+ Extract(Hour From(S.ENDTIME-S.STARTTIME) ) )
WHEN S.endtime IS NULL
THEN NULL
ELSE
Extract(Hour From(S.ENDTIME-S.STARTTIME) ) )
||'hrs' End ||
Extract(Minute From(S.ENDTIME-S.STARTTIME) ) || 'Min' As Hours
FROM Schedule S`
Please note that the data type for endtime and start time is timestamp with timezone in this format:
Nls_Timestamp_Tz_Format='HH24:MI TZR'
Just a question that i would like to ask:
My datatype for hours is varchar2
And if i wish to sum my hours in the end from the results above, would it be tedious in converting it into number?
Thanks
First of all, || Else doesn't make sense. The part after || has to be another expression to concatenate.
Secondly, you certainly can nest case expressions, but in your case you don't need to. A single case expression can have multiple when/then branches, in the form case when [condition_A] then [expression_if_A_is_true] when [condition_B] then [expression_if_A_is_false_and_B_is_true] else [expression_if_A_and_B_are_both_false] end.