SQL request with date - sql

I have a table with data and columns containing a date but separated into several columns :
a column with the year,
a column with the month,
a column with the day.
I would like to keep only the data with a date that is less than 2 months.
I have tried to concat the date but the month and the day does not always have 2 characters. Sometimes it is one number : 1 for january for example.
Could you give some tips to make this request?
Thanks in advance,
select *
from etude
where concat(year,month,day) > NOW()
It is not working as expected

The TIMESTAMP_FORMAT() function should be robust to months/days being either one or two digits:
SELECT *
FROM etude
WHERE TIMESTAMP_FORMAT(CONCAT(year, month, day), 'YYYYMMDD') > NOW();
But note that while this may fix your immediate problem, a much better long term solution would be to stop storing the various components of your date in separate columns. Instead, just maintain a single bona-fide date/timestamp column.

Use lpad function along with timestamp_format function
select *
from etude
where timestamp_format(year || lpad(month,2,'0') || lpad(day,2,'0'), 'YYYYMMDD') > now();

If keep only the data with a date that is less than 2 months means keep only the data with a date that is not earlier than 2 months from the current date, then try this as is:
SELECT dt
FROM
(
SELECT date(digits(dec(year, 4)) || '-' || digits(dec(month, 2))|| '-' || digits(dec(day, 2))) dt
FROM table
(
values
(2019, 1, 1)
, (2019, 7, 13)
) etude (year, month, day)
)
WHERE dt > current date - 2 month;

to combine your 2 questions into 1 answer and using Satya's answer
select *
from etude
where timestamp_format(year || lpad(month,2,'0') || lpad(day,2,'0'), 'YYYYMMDD') > now() - 2 months;

This is another option
select *
from etude
where DATE('0001-12-31') + (year -2) YEARS + month MONTHS + day DAYS > CURRENT DATE

Related

Oracle SQL - Define the year element of a date dependent on the current month

I am trying to create a view in SQL Developer based on this statement:
SELECT * FROM ORDERS WHERE START_DATE > '01-JUL-2020'
The year element of the date needs to set to the year of the current date if the current month is between July and December otherwise it needs to be the previous year.
The statement below returns the required year but I don't know how to incorporate it (or a better alternative) into the statement above:
select
case
when month(sysdate) > 6 then
year(sysdate)
else
year(sysdate)-1
end year
from dual
Thanks
Oracle doesn't have a built-in month function so I'm assuming that is a user-defined function that you've created. Assuming that's the case, it sounds like you want
where start_date > (case when month(sysdate) > 6
then trunc(sysdate,'yyyy') + interval '6' month
else trunc(sysdate,'yyyy') - interval '6' month
end)
Just subtract six months and compare the dates:
SELECT *
FROM ORDERS
WHERE trunc(add_months(sysdate, -6), 'YYYY') = trunc(start_date, 'YYYY')
This compares the year of the date six months ago to the year on the record -- which seems to be the logic you want.

Oracle query to extract data between 2 days for every month

How to extract data between 2 days for every month. For example, say the date range is between 2nd and 10th. Then I need to extract data for 2nd and 10th of every month from the table.
Use EXTRACT
SELECT *
FROM table_name
WHERE EXTRACT( DAY FROM date_column ) BETWEEN 2 AND 10;
or TO_CHAR then TO_NUMBER:
SELECT *
FROM table_name
WHERE TO_NUMBER( TO_CHAR( date_column, 'DD' ) ) BETWEEN 2 AND 10;

How do I convert a Week Number to From date of the week in oracle

Suppose I enter WeekNo: 14 the query should return the From Date: April 4th 2016, since the week 14 starts from 4th April to 10th April
select to_date('14','iw') FROM dual;
something like this ? (it work for current year) there discard data from another years
with dates as (select to_char(
to_date('1.01.'||extract(year from sysdate),'dd.mm.yyyy' ) + level -1
,'IW') we,
to_date('1.01.'||extract(year from sysdate),'dd.mm.yyyy' ) + level -1 da
from dual
connect by level <= 365 + 10 )
select * from (
select case
when -- we = null if number of week in jan > 1,2,3,4....
((to_number(we) > 40 )
and extract(year from sysdate) = extract(year from da)
and extract(month from da) = '01') or
-- we = null when current year < year of da
(extract(year from sysdate) != extract(year from da))
then
null
else we
end we,
da
from dates
)
where we = 14
and rownum = 1
Dealing with ISO-Weeks is not trivial, for example January, 1st 2016 is week 53 of 2015, see
select to_char(date '2016-01-01', 'iyyy-"W"iw') from dual;
So, providing only the week number without the (ISO-) year is ambiguous - although it is obvious as along as you are not around new-years date.
Some time ago I wrote this function to get the date from ISO-Week.
FUNCTION ISOWeekDate(week INTEGER, YEAR INTEGER) RETURN DATE DETERMINISTIC IS
res DATE;
BEGIN
IF week > 53 OR week < 1 THEN
RAISE VALUE_ERROR;
END IF;
res := NEXT_DAY(TO_DATE( YEAR || '0104', 'YYYYMMDD' ) - 7, 'MONDAY') + ( week - 1 ) * 7;
IF TO_CHAR(res, 'fmIYYY') = YEAR THEN
RETURN res;
ELSE
RAISE VALUE_ERROR;
END IF;
END ISOWeekDate;
Of course you can just select NEXT_DAY(TO_DATE( YEAR || '0104', 'YYYYMMDD' ) - 7, 'MONDAY') + ( week - 1 ) * 7;, however this would not be error-safe if somebody uses the wrong year.
If it is not an issue to append the year to the week you are looking for, you can also use this :
SELECT (TRUNC ( TO_DATE (SUBSTR ('201627', 1, 4) || '0131', 'YYYY'|| 'MMDD'), 'IYYY')
+ ( 7 * ( TO_NUMBER (SUBSTR ('201627', 5)) - 1)) ) AS iw_Monday
FROM dual
With in this example 201627 being the YYYYIW you are looking for.
It will return the date of the MONDAY of that week.
Found it on Oracle forums, there are a couple of other solutions there. I found this one to be the most elegant.
The advantage is that you do everything from the SELECT, and you don't need either a function or PL/SQL or a WHERE clause.
Disadvantages : you must append the year and specify your search week 2 times, unless you use a variable
Here is a simple and direct computation, taking advantage of various Oracle date functions. Since it compares to what Oracle already counts as ISO week etc., it shouldn't be subject to any of the difficulties other solutions correctly point to and address with additional code.
The "magic number" 14 in the formula should instead be a bind variable, perhaps :iw, or some other mechanism of inputting the ISO week number into the query.
select trunc(sysdate, 'iw') - 7 * (to_number(to_char(trunc(sysdate), 'iw')) - 14) as dt
from dual;
DT
----------
2016-04-04
1 row selected.

Add days Oracle SQL

SELECT ORDER_NUM, CUSTOMER_NUM, CUSTOMER_NAME, ADD_DAYS (ORDER_DATE, 20)
FROM CUSTOMER, ORDERS;
Oracle Express says ADD_DAYS invalid? Any ideas what Am I doing wrong?
If you want to add N days to your days. You can use the plus operator as follows -
SELECT ( SYSDATE + N ) FROM DUAL;
You can use the plus operator to add days to a date.
order_date + 20
In a more general way you can use "INTERVAL". Here some examples:
1) add a day
select sysdate + INTERVAL '1' DAY from dual;
2) add 20 days
select sysdate + INTERVAL '20' DAY from dual;
2) add some minutes
select sysdate + INTERVAL '15' MINUTE from dual;
Some disadvantage of "INTERVAL '1' DAY" is that bind variables cannot be used for the number of days added. Instead, numtodsinterval can be used, like in this small example:
select trunc(sysdate) + numtodsinterval(:x, 'day') tag
from dual
See also: NUMTODSINTERVAL in Oracle Database Online Documentation
It's Simple.You can use
select (sysdate+2) as new_date from dual;
This will add two days from current date.
One thing about
select (sysdate+3) from dual
is that the sysdate is interpreted as date.
But if you want to use a custom date, not local, you need to make sure it is interpreted as date, not string. Like so (adding 3 days):
select (to_date('01/01/2020')+3) from dual

Oracle query to calculate current age

I want to calculate current age of person from DOB(date of birth) field in Oracle table.
Data type of DOB field is varchar and the is date stored in format 'DD-MON-YY'.
when I calculate current age of a person from date like 10-JAN-49 the query will return age in negative. Also, I observed that if date has year 13 to 49 it gives negative result.
Examples
22-NOV-83 -valid result
09-FEB-58 --valid result
05-JUN-49 - Invalid result like -36
Query Executed for reference
select round(MONTHS_BETWEEN(sysdate,to_date(dob,'DD-MON-RR'))/12)||' Yrs'
from birth
Any help is appreciated!
To get round the 21st century problem, just modifying #the_silk's answer slightly:
SELECT
CASE WHEN SUBSTR(dob, -2, 2) > 13
THEN FLOOR
(
MONTHS_BETWEEN
(
SYSDATE
, TO_DATE(SUBSTR(dob, 1, 7) || '19' || SUBSTR(dob, -2, 2), 'DD-MON-YYYY')
) / 12
)
ELSE
FLOOR(MONTHS_BETWEEN(sysdate,TO_DATE(dob,'DD-MON-YY'))/12)
END
FROM
birth
Please be aware though that this assumes that any date year between '00' and '13' is 21st century, so this sql should only be used if you are building a one off throwaway script, otherwise it will become out of date and invalid before long.
The best solution would be to rebuild this table, converting the varchar column into a date column, as alluded to by Ben.
/*
A value between 0-49 will return a 20xx year.
A value between 50-99 will return a 19xx year.
*/
Source: http://www.techonthenet.com/oracle/functions/to_date.php
SELECT FLOOR
(
MONTHS_BETWEEN
(
SYSDATE
, TO_DATE(SUBSTR(d_date, 1, 7) || '19' || SUBSTR(d_date, -2, 2), 'DD-MON-YYYY')
) / 12
)
FROM
(
SELECT '10-JAN-49' d_date FROM DUAL
)
-- The result: 64
SELECT MONTHS_BETWEEN( to_date(sysdate,'dd-mm-rr')
, to_date(to_date(dob,'yymmdd'),'dd-mm-rr')
) / 12 AS Years
FROM birth;
Maybe this works.
My solution would be something like this:
SELECT DATE_FORMAT(CURDATE(),'%Y') - DATE_FORMAT(dob,'%Y') as age
FROM `member_master`
having age >=30 and age <=35
SELECT year,
months,
Floor(SYSDATE - day_1) AS days
FROM (SELECT year,
months,
Add_months(To_date('30-Oct-1980', 'dd-Mon-yyyy'),
12 * year + months)
day_1
FROM (SELECT year,
Floor(Trunc(Months_between(Trunc(SYSDATE),
To_date('30-Oct-1980', 'dd-Mon-yyyy')
))
- year * 12) AS months
FROM (SELECT Floor(Trunc(Months_between(Trunc(SYSDATE),
To_date('30-Oct-1980',
'dd-Mon-yyyy'
)
)) /
12) AS year
FROM dual)));
Try using YY in the Year part of your TO_DATE
RR Like YY, but the two digits are ``rounded'' to a year in the range 1950 to 2049. Thus, 06 is considered 2006 instead of 1906