Oracle - display all within next 12 months - oracle

I am trying to pull all data within the next 12 months only. the only thing i can find online is "addmonths" but can't get it, not sure if it's because the date in the Start_date column is DD/MM/YYYY?
select number, start_date from wo_table
where start_date between sysdate and addmonths(sysdate,12)

SELECT "number", start_date
FROM wo_table
WHERE start_date BETWEEN SYSDATE
AND ADD_MONTHS( SYSDATE, 12 );
Or
SELECT "number", start_date
FROM wo_table
WHERE start_date BETWEEN SYSDATE
AND SYSDATE + INTERVAL '1' YEAR;

figured it out for future reference incase it helps others:
select number, start_date from wo_table
where start_date between sysdate and sysdate+365
simple :)

Related

Applying case statement on date

I am working on reports where we have activity start date(Date when the activity has begun) and activity end date(When the activity ended). I have a requirement wherein if the activity has begun before 2021 then I have to set the start date as 1/1/21 and if it continues after 2021 then set the activity end date as 31/12/21.And if the start date and end date lie in the same year keeping them as it is.
How can I achieve this scenario.
You do not need a CASE expression; you can use GREATEST and LEAST:
UPDATE table_name
SET start_date = GREATEST(start_date, DATE '2021-01-01'),
end_date = LEAST(end_date, TIMESTAMP '2021-12-31 23:59:59')
WHERE start_date < DATE '2022-01-01'
AND ( start_date < DATE '2021-01-01'
OR end_date >= DATE '2022-01-01');
If you want to just select the values where the date range overlaps 2021, and limit the range to be from 2021, then:
SELECT column1,
column2,
GREATEST(start_date, DATE '2021-01-01') AS start_date,
LEAST(end_date, TIMESTAMP '2021-12-31 23:59:59') AS end_date
FROM table_name
WHERE start_date < DATE '2022-01-01'
AND end_date >= DATE '2021-01-01'
If you want a generic query for any given year, starting from the :year_start bind variable, then:
SELECT column1,
column2,
GREATEST(start_date, :year_start) AS start_date,
LEAST(end_date, ADD_MONTHS(:year_start, 12) - INTERVAL '1' SECOND) AS end_date
FROM table_name
WHERE start_date < ADD_MONTHS(:year_start, 12)
AND end_date >= :year_start;

Loop Insert Date a daily commit day to day timestamp ORACLE

im executing query in oracle. i need insert data everyday commit in looping like this :
DECLARE
start_date NUMBER;
end_date NUMBER;
business_date VARCHAR2 (8);
BEGIN
start_date := TO_NUMBER (TO_CHAR (TO_DATE ('2017-01-01', 'yyyy-MM-dd')));
end_date := TO_NUMBER (TO_CHAR (TO_DATE ('2018-01-01', 'yyyy-MM-dd')));
FOR cur_r IN start_date .. end_date
LOOP
INSERT INTO file_backup
SELECT *
FROM file_core
WHERE TO_NUMBER (TO_CHAR (TO_DATE (datecreated, 'yyyy-MM-dd')))>=start_date+cur_r
AND TO_NUMBER (TO_CHAR (TO_DATE (datecreated, 'yyyy-MM-dd')))<=end_date;
COMMIT;
END LOOP;
END;
I dunt know error this script .. please help me .. btw i newbie in oracle sorry ..
As #boneist pointed out, your manipulation using numbers isn't going to work. You should keep the data type as it is and compare with values of the same data type.
Assuming you have a legitimate need to do this in a loop you could do something like this:
BEGIN
FOR r IN (
select date '2017-01-01' + level -1 as this_date
from dual
connect by level <= date '2018-01-01' - date '2017-01-01'
)
LOOP
INSERT INTO file_backup
SELECT *
FROM file_core
WHERE datecreated >= r.this_date
AND datecreated < r.this_date + 1;
COMMIT;
END LOOP;
END;
/
Or if the data type is actually a timestamp rather than a date as suggested in a comment, something like:
BEGIN
FOR r IN (
select timestamp '2017-01-01 00:00:00'
+ (level -1) * interval '1' day as this_timestamp
from dual
connect by level <= extract(day from timestamp '2018-01-01 00:00:00'
- timestamp '2017-01-01 00:00:00')
)
LOOP
INSERT INTO file_backup
SELECT *
FROM file_core
WHERE datecreated >= r.this_timestamp
AND datecreated < r.this_timestamp + interval '1' day;
COMMIT;
END LOOP;
END;
/
... though you might want to work on the condition for the connect-by query, e.g.
FOR r IN (
select timestamp '2017-01-01 00:00:00'
+ numtodsinterval(level -1, 'DAY') as this_timestamp
from dual
connect by timestamp '2017-01-01 00:00:00'
+ numtodsinterval(level -1, 'DAY') < timestamp '2018-01-01 00:00:00'
)
LOOP
...
or as #boneist suggested in a comment, with a simpler loop:
BEGIN
FOR num_days in 0..(date '2018-01-01' - date '2017-01-01' - 1)
LOOP
INSERT INTO file_backup
SELECT *
FROM file_core
WHERE datecreated >= timestamp '2017-01-01 00:00:00'
+ numtodsinterval(num_days, 'DAY')
AND datecreated < timestamp '2017-01-01 00:00:00'
+ numtodsinterval(num_days + 1, 'DAY');
COMMIT;
END LOOP;
END;
/
The main problem with this approach is restartability. If there is an error part way through the loop you can't just re-run it, as you'd be inserting duplicates.
Multiple inserts and commits are also less efficient that a single insert, or even multiple inserts and a single commit. If you don't have enough undo space to allow a single transaction to do all the work you need you should be fixing the database configuration to allow that, rather than working around it and potentially compromising data integrity.
i need backup this table . and insert only 2 month in new table
That sounds like you need to partition the table by month and use partition swaps to shift old months from the live to the backup table, perhaps. Partitioning costs more but if you have those data volumes it may be justified.
Failing that you could consider renaming your current table to backup, recreating your original table, and just copying the two months' worth of data you want to keep back to that. But that's a one-off thing, you still have the ongoing problem of ageing records out of the main table and into backup. And it has its own issues with dependencies, constraints, etc.
You don't need any loop and you should skip all these TO_CHAR, TO_NUMBER, TO_DATE conversions. Try this:
INSERT INTO file_backup
SELECT *
FROM file_core
WHERE datecreated BETWEEN DATE '2017-01-01' AND DATE '2018-01-01';
Perhaps datecreated has time values different to 00:00:00, in this case you should run
INSERT INTO file_backup
SELECT *
FROM file_core
WHERE TRUNC(datecreated) BETWEEN DATE '2017-01-01' AND DATE '2018-01-01';
or in case datecreated is a VARCHAR2 data type rather than DATE run
INSERT INTO file_backup
SELECT *
FROM file_core
WHERE TO_DATE(datecreated, 'YYYY-MM-DD') BETWEEN DATE '2017-01-01' AND DATE '2018-01-01';
Assuming your datecreated column is of data type DATE and you only want one copy of the rows of the table then you do not need PL/SQL:
INSERT INTO file_backup
SELECT *
FROM file_core
WHERE datecreated BETWEEN DATE '2017-01-01' AND DATE '2018-01-01';
COMMIT;
You could use a DATE literal to set the start_date and end_date and use a loop like this.
DECLARE
start_date NUMBER;
end_date NUMBER;
BEGIN
start_date := DATE '2017-01-01';
end_date := DATE '2018-01-01';
FOR cur_r IN 0 .. (end_date - start_date)
LOOP
INSERT INTO file_backup
SELECT *
FROM file_core
WHERE TRUNC (datecreated) = start_date + cur_r;
COMMIT;
END LOOP;
END;
Why wouldn't you do it using a simple INSERT, such as
INSERT INTO file_backup
SELECT *
FROM file_core
WHERE datecreated BETWEEN DATE '2017-01-01' AND DATE '2018-01-01';
If you're just practicing PL/SQL and loops, well, remove COMMIT out of the LOOP. Both START and END_DATE should be "converted" to a number using a proper format mask (i.e. yyyymmdd). FOR loop's index should go from 1 to a difference between END and START_DATE.
[EDITED, after reading MT0's comment]
[EDITED #2, after reading some more comments]
Bah, my code is rubbish, should've thought about what I'm doing. Basically, if I meant to write it properly, it would have looked like #Kaushik Nayak's, and there's really no point in doing it twice.

Retrieving date list from Oracle database

I have a table like this
Start_Date End_Date
----------------------------------------------------
21-02-2016 11:04:41 23-02-2016 11:04:41
21-02-2016 14:03:29 25-02-2016 14:03:29
22-02-2016 14:03:29 25-02-2016 14:03:29
If input is 21-Feb-2016 then I want to fetch all the rows if the given input falls between the Start_Date and End_Date. In these case the output should be
Output (truncating the time part)
Start_Date End_Date
------------------------------------------------
21-02-2016 23-02-2016
21-02-2016 25-02-2016
I tried the below query but somehow it didn't return the required result:
Select Start_Date, End_Date
from TEST
where Start_Date <= 21-02-2016 and End_Date >= 23-02-2016
Can someone tell me where I have made mistake and provide a proper solution for it
If your table fields are in date format, you need something like the following:
select *
from test
where to_date('21-02-2016', 'dd-mm-yyyy') between trunc(start_date) and trunc(end_date)
Otherwise, if they are stored as strings ( and I hope not) you need:
select *
from test
where to_date('21-02-2016', 'dd-mm-yyyy') between
trunc( to_date(start_date,'dd-mm-yyyy hh24:mi:ss') ) and
trunc( to_date(end_date, 'dd-mm-yyyy hh24:mi:ss') )
Maybe you should also use the trunc function to filter the dates
Select Start_Date,End_Date from TEST
where to_date('21-02-2016','dd-mm-yyyy') between trunc(start_date) and trunc(end_date)
SELECT DISTINCT
TRUNC( start_date ) AS truncated_start_date,
TRUNC( end_date ) AS truncated_end_date
FROM your_table
WHERE DATE '2016-02-21' BETWEEN TRUNC( start_date ) AND TRUNC( end_date )

Get date of the previous day in Oracle

I need to bring the day immediately preceding date in Oracle using a truncate but not how. He was using the following line but bring me some records for the current day of execution and should not be. Neceisto only the previous day; investigation found the truncate with dates in Oracle but not how to use it.
and fnxs.FECHA_INGRESO BETWEEN (TO_CHAR (SYSDATE-1, 'DD-MON-YY')) AND (TO_CHAR (SYSDATE, 'DD-MON-YY'));
I appreciate your help
Using BETWEEN with dates in Oracle is generally a bad idea. I see it all the time, and most of the time people get it wrong (like in the accepted answer above). Even when they fully understand that the two dates are included, they still make logical errors because they forget about timestamps.
The OP is asking for yesterday dates. The following sql shows that today falls within "BETWEEN TRUNC( SYSDATE ) - 1 AND TRUNC( SYSDATE )"
with adate as (
select trunc(sysdate) today from dual
) select today from adate where today between trunc(sysdate) -1
and trunc(sysdate);
16-Apr-15 00:00:00
[returns the record for today]
I find it easier to be correct with dates when you're more explicit about the end points:
SELECT * from your_table
WHERE fnxs.FECHA_INGRESO >= TRUMC(SYSDATE) - 1
AND fnxs.FECHA_INGRESO < TRUNC(SYSDATE);
Upon looking closer, the OP's date-like column might be a VARCHAR2 (could still be a date that was implicitly cast in the comparison he gave). If it is a VARCHAR, then it needs to be converted first (using an appropriate format string):
SELECT * FROM your_table
WHERE TO_DATE(fnxs.FECHA_INGRESO, 'DD-MON-YY') >= TRUMC(SYSDATE) - 1
AND TO_DATE(fnxs.FECHA_INGRESO, 'DD-MON-YY') < TRUNC(SYSDATE);
Assuming your column is of type DATE
SELECT *
FROM TABLE_NAME
WHERE FECHA_INGRESO BETWEEN TRUNC( SYSDATE ) - 1
AND TRUNC( SYSDATE );
If it is a character string then:
SELECT *
FROM TABLE_NAME
WHERE TO_DATE( FECHA_INGRESO, 'DD-MON-YY' )
BETWEEN TRUNC( SYSDATE ) - 1
AND TRUNC( SYSDATE );

Date function on oracle

I've got a question about date function on oracle.
I have the following table
statistic_table(
pages AS varchar(10),
date_created AS date
);
I have the following sql
SELECT COUNT(*) FROM statistic_table WHERE date_created BETWEEN sysdate-5 AND sysdate-1
and
SELECT COUNT(*) FROM statistic_table WHERE date_created BETWEEN to_date('12-AUG-2011') AND to_date('16-AUG-2011');
the question is, why is it return different numbers. assuming sysdate-5 returns 12-aug-2011 and sysdate-1 returns 16-aug-2011
Any help would be much appreciated!
Cheers,
sysdate - 5 will give you a date with the current time. So if I ran it at 1pm precisely, the query would be equivalent to:
select (*)
FROM statistic_table
WHERE date_created BETWEEN to_date('12-Aug-2011 13:00:00')
AND to_date('16-Aug-2011 13:00:00')
whereas the second query is:
select (*)
FROM statistic_table
WHERE date_created BETWEEN to_date('12-Aug-2011 00:00:00')
AND to_date('16-Aug-2011 00:00:00')
you should probably try this instead:
select (*)
FROM statistic_table
WHERE date_created BETWEEN trunc(sysdate) -5
AND trunc(sysdate) -1
A date in Oracle is a point in time with a precision of a second.
SYSDATE returns the current date and time and is therefore not the same as to_date('17-AUG-2011'):
SQL> SELECT to_char(sysdate, 'dd-mon-yyyy hh24:mi:ss') FROM DUAL;
TO_CHAR(SYSDATE,'DD-MON-YYYYHH
------------------------------
17-aug-2011 15:52:13
Use the TRUNC function if you only want the date component:
SQL> SELECT to_char(trunc(sysdate), 'dd-mon-yyyy hh24:mi:ss') FROM DUAL;
TO_CHAR(TRUNC(SYSDATE),'DD-MON
------------------------------
17-aou-2011 00:00:00
Because SYSDATE includes a time component, so if the current time is 11:22:33, then
SELECT COUNT(*) FROM statistic_table
WHERE date_created BETWEEN sysdate-5 AND sysdate-1
is actually equivalent to
SELECT COUNT(*) FROM statistic_table
WHERE date_created BETWEEN to_date('12-AUG-2011 11:22:33','DD-MON-YYYY HH24:MI:SS')
AND to_date('16-AUG-2011 11:22:33','DD-MON-YYYY HH24:MI:SS')
To avoid the time component do this:
SELECT COUNT(*) FROM statistic_table
WHERE date_created BETWEEN TRUNC(sysdate)-5 AND TRUNC(sysdate)-1
An Oracle DATE always has a day and a time component.
sysdate-5 returns a date exactly 5 days ago. If today is August 17 at 10 AM, for example, sysdate-5 returns August 12 at 10 AM.
to_date('12-AUG-2011', 'DD-MON-YYYY'), on the other hand, returns August 12 at midnight. So it returns a date that is 10 hours earlier than sysdate-5.
sysdate auto returns with a time component as mentioned by the previous answers.
When using to_date it is converting a string to a date. With this being said you can pass in parameters to make it return the same thing.
Have a look at this link that explains it.
to_date parameters

Resources