current year's date of birth using oracle sql - sql

Trying to get birth day date in the current year.
For an example if DOB=19800925, birth day in the current year is 20180925
(note: we should not just replace the year because of the leap year DOB (ex: 20000229))
with tmp_dob as
(
select '19900101' Birthday from dual union all
select '19901231' Birthday from dual union all
select '20040229' Birthday from dual union all
select '20041231' Birthday from dual union all
select '20171231' Birthday from dual union all
select '20051231' Birthday from dual
)
select Birthday,add_months(to_date(Birthday,'YYYYMMDD'),(trunc(months_between(sysdate ,to_date(Birthday,'YYYYMMDD'))/12)) * 12) current_year_dob
from tmp_dob;

This logic should work:
with tmp_dob as (
select to_date('19900101', 'YYYYMMDD') as Birthday from dual union all
select to_date('19901231', 'YYYYMMDD') Birthday from dual union all
select to_date('20040229', 'YYYYMMDD') Birthday from dual union all
select to_date('20041231', 'YYYYMMDD') Birthday from dual union all
select to_date('20171231', 'YYYYMMDD') Birthday from dual union all
select to_date('20051231', 'YYYYMMDD') Birthday from dual
)
select Birthday,
add_months(birthday, 12 * (extract(year from sysdate) - extract(year from birthday)))
from tmp_dob;

Add months approach works, but you'll get 2/28 for the leap-day birthdays. If you want that to be 03/01, or to be configurable, use a case to detect the condition and override:
with tmp_dob as (
select to_date('19900101', 'YYYYMMDD') as Birthday from dual union all
select to_date('19901231', 'YYYYMMDD') Birthday from dual union all
select to_date('20040229', 'YYYYMMDD') Birthday from dual union all
select to_date('20041231', 'YYYYMMDD') Birthday from dual union all
select to_date('20171231', 'YYYYMMDD') Birthday from dual union all
select to_date('20051231', 'YYYYMMDD') Birthday from dual
)
select Birthday,
case
when
to_date(extract(year from sysdate) || '1231', 'YYYYMMDD') -
to_date(extract(year from sysdate) || '0101', 'YYYYMMDD') < 365
and to_char(birthday, 'MMDD') = '0229' then
to_date(extract(year from sysdate) || '0301', 'YYYYMMDD')
else
add_months(birthday, 12 * (extract(year from sysdate) - extract(year from birthday)))
end as bd_this_year
from tmp_dob;
Results:
BIRTHDAY BD_THIS_YEAR
1/1/1990 1/1/2018
12/31/1990 12/31/2018
2/29/2004 3/1/2018
12/31/2004 12/31/2018
12/31/2017 12/31/2018
12/31/2005 12/31/2018
Consider making a function to do the same thing - your query will be easier to read.

I thought about using an approach of strings since the birthdays you are using are on strings too.
I use the BigQuery Syntax but there should be similar functions in every SQL.
with tmp_dob as
(
select '19900101' Birthday from dual union all
select '19901231' Birthday from dual union all
select '20040229' Birthday from dual union all
select '20041231' Birthday from dual union all
select '20171231' Birthday from dual union all
select '20051231' Birthday from dual
)
select Birthday,
CASE WHEN MOD(CAST(SUBSTR(Birthday,1,4) AS INT64), 4) = 0 AND SUBSTR(Birthday,5,8) = '0229'
THEN CONCAT(CAST(EXTRACT(YEAR FROM CURRENT_DATE) AS STRING), '0228')
ELSE CONCAT(CAST(EXTRACT(YEAR FROM CURRENT_DATE) AS STRING), SUBSTR(Birthday,5,8)) END AS bd
from tmp_dob;

Related

Converting Day of the Year to a date when some date formats have DDYYYY and some have DDDYYYY in oracle

So I am trying to convert some Day of the Year dates to Date format. The problem is some day of the year dates are in DDYYYY format for days under 100 and DDDYYYY format for days 100 and over. I have tried the following but still receive a "day of year must be between 1 and 365 (366 for leap year)" error:
select CASE when data_Date >= 999999
then to_date(data_date, 'DDDYYYY')
when data_Date >= 99999
then to_date(data_Date, 'DDYYYY')
else to_date(data_date, 'DYYYY')
END as DATA_DATE_CONVERTED
from table;
Thanks in advance
Sample Data is as follows:
Data_date (being passed in as a varchar2)
1072015
12017
612014
672013
72017
1112018
The last 4 digit is the year. Use LPAD to put leading zeroes on DAY
select to_date( lpad(dayyear, 7, '0'),'DDDYYYY')
from table;
sqlfiddle
How about this:
with demo (data_date) as
( select 1072015 from dual union all
select 12017 from dual union all
select 612014 from dual union all
select 672013 from dual union all
select 72017 from dual union all
select 1112018 from dual )
select data_date
, to_char(data_date,'0000000')
, to_date(to_char(data_date,'0000000'),'DDDYYYY') as data_date_converted
from demo
You can also put a dash (-) between.
with demo (data_date) as
( select 1072015 from dual union all
select 12017 from dual union all
select 612014 from dual union all
select 672013 from dual union all
select 72017 from dual union all
select 1112018 from dual )
select data_date, TO_DATE(SUBSTR(data_date, 1, length(data_date)-4)||'-'||SUBSTR(data_date, -4, 4), 'DDD-YYYY')
from demo;

Closest Date to a given date - SQL Oracle

Oracle (SQL) - I have 3 available dates in a month (1st, 10th and 25th). I need a query to find out the closest among the 3 dates based on the date of executing my query. For e.g, when i run the query on 4th, i should get 10th as my result, when i run on 12th, the result should be 25th and when i run on 27th, the result should be the 01st of next month.
I am struggling with the logic. Please help..
with
inputs ( dt ) as (
select to_date( '03/24/2015 11:30:00', 'mm/dd/yyyy hh24:mi:ss') from dual union all
select to_date( '08/03/2016 07:15:00', 'mm/dd/yyyy hh24:mi:ss') from dual union all
select to_date( '02/29/2016 22:30:00', 'mm/dd/yyyy hh24:mi:ss') from dual
)
-- End of simulated inputs (for testing only, not part of the solution).
-- SQL query begins BELOW THIS LINE. Use your actual table and column names.
select dt,
case when extract(day from dt) < 10 then trunc(dt, 'mm') + interval '9' day
when extract(day from dt) < 25 then trunc(dt, 'mm') + interval '24' day
else add_months(trunc(dt, 'mm'), 1)
end as next_std_dt
from inputs;
DT NEXT_STD_DT
------------------- -------------------
03/24/2015 11:30:00 03/25/2015 00:00:00
08/03/2016 07:15:00 08/10/2016 00:00:00
02/29/2016 22:30:00 03/01/2016 00:00:00
I believe this is much more efficient and simpler than the other solutions.
WITH
possible_dates
AS
-- generate the three available dates for the current month
(SELECT TRUNC (SYSDATE, 'MM') available_date
FROM DUAL
UNION ALL
SELECT TRUNC (SYSDATE, 'MM') + 9
FROM DUAL
UNION ALL
SELECT TRUNC (SYSDATE, 'MM') + 24
FROM DUAL
UNION ALL
SELECT ADD_MONTHS (TRUNC (SYSDATE, 'MM'), 1)
FROM DUAL),
delta
AS
-- calculate the distance of those available dates
(SELECT (available_date - SYSDATE) diff, available_date
FROM possible_dates)
SELECT *
FROM delta
WHERE diff = (SELECT MIN (diff)
FROM delta
WHERE diff >= 0);
If using PL SQL is an option, then use the query as following:
`DECLARE
curr_month CHAR(2);
curr_year CHAR(4);
future_date DATE;
BEGIN
select to_char(sysdate, 'MM') INTO curr_month from dual;
select to_char(sysdate, 'YYYY') INTO curr_year from dual;
future_date := TO_DATE('12' || curr_month || curr_year, 'DD/MM/YYYY');
IF (SYSDATE > future_date) THEN
{..whatever you want to do...}
ELSIF (SYSDATE > future_date2) THEN
{..whatever you want to do...}
END IF;
END;`
WITH mytable(dt) AS
(SELECT '01'
FROM dual
UNION ALL SELECT '10'
FROM dual
UNION ALL SELECT '25'
FROM dual),
given_dates AS
(SELECT Trunc (To_date (dt || To_char(sysdate, 'MMYYYY'), 'DDMMYYYY')) dt,
Trunc(sysdate) cdate
FROM mytable),
comp AS
(SELECT cdate,
CASE
WHEN ABS (cdate - dt) < ABS (cdate - Add_months (dt, 1)) THEN dt
ELSE Add_months (dt, 1)
END dt_comp
FROM given_dates)
SELECT dt_comp closest_date
FROM
(SELECT dt_comp,
rank() OVER (
ORDER BY ABS (cdate - dt_comp)) rn
FROM comp)
WHERE rn = 1;

Oracle order by year, month

I have a query which I want to order by year and then month. I have tryed order by to_date( depdate, 'mm' ) and TO_CHAR(depdate, 'YYYY/MM'). Here is an sqlfiddle to the table i am querying and the query itself sqlfiddle
You want to sort by the date value, not by the character string representation. That means that you also want to group by the date value. trunc(<<date column>>, 'mm') truncates a date to midnight on the first of the month. So something like this
SELECT to_char(trunc(DEPDATE,'MM'), 'Mon-YYYY') AS MONTH,
SUM(AMOUNTROOM) AS ROOMTOTAL,
SUM(AMOUNTEXTRAS) AS EXTRATOTAL,
SUM(AMOUNTEXTRAS + AMOUNTROOM) AS OATOTAL
FROM checkins
WHERE checkinstatus = 'D' AND depdate > TO_DATE('2013-12-01', 'yyyy/mm/dd')
AND depdate <= TO_DATE('2014-04-10', 'yyyy/mm/dd')
GROUP BY trunc(depdate,'mm')
ORDER BY trunc(depdate,'mm');
should be what you're looking for. See the updated fiddle
Check out this query. If it is a date field, just plain order by would work for you. You need not use TO_CHAR to convert to string and then sort:
WITH TAB AS
(
SELECT SYSDATE DATEVAL FROM DUAL
UNION
SELECT SYSDATE + 100 DATEVAL FROM DUAL
UNION
SELECT SYSDATE -500 DATEVAL FROM DUAL
UNION
SELECT SYSDATE + 30 DATEVAL FROM DUAL
UNION
SELECT SYSDATE -30 DATEVAL FROM DUAL
) SELECT * FROM TAB
ORDER BY DATEVAL DESC

How to check date lies in the month from JAN to JUNE and JULY to DECEMBER

I have a date. I want to check whether the date lies between JAN to JUNE or JULY to DECEMBER. Like suppose if user enter input date 28-NOV-12 then how can i check that this date lies between JULY to DECEMBER ? and if user input date 28-FEB-12 then this date lies between JAN to JUNE? Basically i want to check dates on half yearly basis ?
Thanks
select sign(2.5-to_char(<date>, 'q')) from dual;
returns 1 for dates between January 1st and June 30th and -1 otherwise.
Explanation:
to_char(date, 'q') returns the Quarter of year (1, 2, 3, 4; January - March = 1) of date (see format models). For November 28th, that would be 4.
2.5-quarter returns a negative number for quarter 3 and 4, and a positive number for quarter 1 and 2, respectively. The sign reduces the negative and positive numbers to a simpler -1 and 1.
Testcase:
with da as (
select date '2012-01-01' te from dual union all
select date '2012-02-02' te from dual union all
select date '2012-03-03' te from dual union all
select date '2012-04-04' te from dual union all
select date '2012-05-05' te from dual union all
select date '2012-06-06' te from dual union all
select date '2012-07-07' te from dual union all
select date '2012-08-08' te from dual union all
select date '2012-09-09' te from dual union all
select date '2012-10-10' te from dual union all
select date '2012-11-11' te from dual union all
select date '2012-12-12' te from dual
)
select
da.te,
decode (sign(2.5-to_char(da.te, 'q')),
1, 'Jan-Jun',
-1, 'Jul-Dec')
from da;
Try to_char function, e.g. this way:
select
case
when to_char(date_column, 'mm') <= 6 then '1st'
when to_char(date_column, 'mm') >= 7 then '2nd'
end as half_of_the_year
from your_table
to_char(date_column, 'mm') returns month (01..12, 01 - January) part of the date.
select
case
when to_char(sysdate, 'mm') <= 6 then '1st'
when to_char(sysdate, 'mm') >= 7 then '2nd'
end as half_of_the_year
from dual
today returns:
HALF_OF_THE_YEAR
2nd
select * from table "28-NOV-2012" WHERE date_column between TO_DATE('01-JAN-2012') AND TO_DATE('01-JUN-2012');
Try this ,date_column should be date datatype other wise change to TO_DATE(date_column)
select
case
when date_column BETWEEN TO_DATE('01-JAN-12') AND TO_DATE('03-JUN-12')then '1st Half'
ELSE '2nd Half'
end as DatePosition
from table_name

How do update a date column by changing only the year and not the day or month using PLSQL?

I have a database table containing credit card records. One of the fields is a Date field. I would like to update this field by changing the year portion of the date to 2011 if the year is less than 2010. From what i have found, PLSQL has functions for time and months but nothing to do with years (to my knowledge).
This shows how to
with cc as(
select to_date('12-jan-1999') as cdate from dual union all
select to_date('12-jan-1921') as cdate from dual union all
select to_date('12-jan-1900') as cdate from dual union all
select to_date('12-jan-2000') as cdate from dual union all
select to_date('12-jan-2010') as cdate from dual
)
select to_date( to_char(cdate,'DD-MON') ||'-2011','DD-MON-YYYY')
from cc
where cdate < to_date('01-JAN-2010','DD-MON-YYYY')
/
1 year = 12 months, so subtract 12 months:
select add_months(sysdate,-12) from dual
Here's how to do it so it works with leap years using add_months.
with cc as(
select to_date('12-jan-1999','dd-mon-yyyy') as cdate from dual union all
select to_date('12-jan-1921','dd-mon-yyyy') as cdate from dual union all
select to_date('29-feb-1904','dd-mon-yyyy') as cdate from dual union all
select to_date('12-jan-2000','dd-mon-yyyy') as cdate from dual union all
select to_date('12-jan-2010','dd-mon-yyyy') as cdate from dual
)
select add_months(cdate,(2011 - extract( year from cdate)) * 12)
from cc
where cdate < to_date('01-JAN-2010','DD-MON-YYYY');