Retrieving date list from Oracle database - oracle

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 )

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;

Coalesce statement to handle multiple values and NULLS?

I am trying to figure out how to create an SQL query that will check for (:FROM_DATE) and (:TO_DATE) parameters and if NULL to put the past month dates in for the two values, and if not NULL to accept whatever values are entered in the parameters.
For example:
if the user enters (01-JAN-17) as FROM_DATE, and (31-JAN-17) as TO_DATE, I want the query to not automatically pass any values for the TO_DATE and FROM_DATE.
if the user does not enter any values for TO_DATE and FROM_DATE or there are NULL values passed in, I want the query to automatically enter the the past months values (i.e., if query is run July 1st 2017, the FROM_DATE would be 01-JUN-17 and the TO_DATE would be 30-JUN-17).
I was hinted to use a coalesce statement to handle multiple values and NULLS (i.e., AND ( (coalesce(null, :P_ORG) is null) or (ORG.ORGANIZATION_ID in :P_ORG)))???
Any help would be greatly appreciated.
Something like:
SELECT *
FROM your_table
WHERE your_date_column BETWEEN TO_DATE( :from_date, 'DD-MON-YYYY' )
AND TO_DATE( :to_date, 'DD-MON-YYYY' )
OR ( ( :from_date IS NULL OR :to_date IS NULL )
AND your_date_column BETWEEN ADD_MONTHS( TRUNC( SYSDATE, 'MM' ), -1 )
AND TRUNC( SYSDATE, 'MM' ) - 1
);
If either (or both) :from_date or :to_date is NULL then the dates will be compared to the previous month.
If your table has dates where the time component is not always set to midnight then you will need to use:
SELECT *
FROM your_table
WHERE your_date_column BETWEEN TO_DATE( :from_date, 'DD-MON-YYYY' )
AND TO_DATE( :to_date, 'DD-MON-YYYY' )
OR ( ( :from_date IS NULL OR :to_date IS NULL )
AND your_date_column >= ADD_MONTHS( TRUNC( SYSDATE, 'MM' ), -1 )
AND your_date_column < TRUNC( SYSDATE, 'MM' )
);
Proof of concept: consider the following query, where we have dates and values, and we want to sum the values for the dates that fall between :from_date and :to_date. If either of them is null, the query will use the first day of the prior month for from_date and the last day of the prior month for to_date. Note that this will cause problems if one date is given an actual value and the other is left null - you didn't explain how you would want that handled. But that's a different issue.
I use SQL developer, and in it I don't know how to pass in dates; I show passing in strings, and converting them to dates.
with
test_data ( dt, val ) as (
select date '2017-05-29', 200 from dual union all
select date '2017-06-13', 150 from dual union all
select date '2017-06-18', 500 from dual
)
select sum(val) as sum_val
from test_data
where dt between coalesce(to_date(:from_date, 'yyyy-mm-dd'),
add_months(trunc(sysdate, 'mm'), -1))
and coalesce(to_date(:to_date , 'yyyy-mm-dd'), trunc(sysdate, 'mm') - 1)
;
Yes, you can use COALESCE (or Oracle's NVL). When a parameter is null, replace it with the default date.
select *
from mytable
where mydate >= coalesce(:from_date, trunc(sysdate - interval '1' month), 'month')
and mydate <= coalesce(:to_date, last_day(sysdate - interval '1' month));

Calculate average values in Oracle

I want to calculate average values in Oracle tables
CREATE TABLE AGENT_HISTORY(
EVENT_ID INTEGER NOT NULL,
AGENTID INTEGER NOT NULL,
EVENT_DATE DATE NOT NULL
)
/
CREATE TABLE CPU_HISTORY(
CPU_HISTORY_ID INTEGER NOT NULL,
EVENT_ID INTEGER NOT NULL,
CPU_NAME VARCHAR2(50 ) NOT NULL,
CPU_VALUE NUMBER NOT NULL
)
/
I use this SQL query:
----- FOR 24 HOURS CPU
CURSOR LAST_24_CPU_CURSOR IS
--SELECT EVENT_DATE, CPU FROM AGENT_HISTORY WHERE NAME = NAMEIN AND EVENT_DATE >= SYSDATE-(60*24)/1440;
SELECT START_DATE, NVL(AVG(CH.CPU_VALUE),0)
FROM (SELECT START_DATE - (LVL+1)/24 START_DATE, START_DATE - LVL/24 END_DATE
FROM (SELECT SYSDATE START_DATE, LEVEL LVL FROM DUAL CONNECT BY LEVEL <= 24))
LEFT JOIN AGENT_HISTORY AH ON EVENT_DATE BETWEEN START_DATE AND END_DATE
LEFT JOIN CPU_HISTORY CH ON AH.EVENT_ID = CH.EVENT_ID
JOIN AGENT AG ON AH.AGENTID = AG.ID
WHERE AG.NAME = NAMEIN
GROUP BY START_DATE
ORDER BY 1;
This query prints only one average value. I would like to modify it to print 24 values for every hour average value. Can you help me to modify the query?
I guess your input contains data only for one of the given intervals; since you're using an INNER JOIN with AGENT which in turn is filtered by AGENT_HISTORY, you're effectively converting all your LEFT JOINs to inner ones.
I suggest you use a CROSS JOIN between AGENT and the timeslots instead:
with agent_history(event_date, agentid, event_id) as (
select timestamp '2015-11-18 09:00:07', 1, 1001 from dual
),
agent(id, name) as (
select 1, 'myAgent' from dual
),
cpu_history(event_id, cpu_value) as (
select 1001, 75.2 from dual
),
time_slots(start_date, end_date) as (
SELECT START_DATE - (LVL + 1) / 24 START_DATE,
START_DATE - LVL / 24 END_DATE
FROM (SELECT SYSDATE START_DATE,
LEVEL LVL
FROM DUAL
CONNECT BY LEVEL <= 24)
)
SELECT START_DATE,
NVL(AVG(CH.CPU_VALUE),
0)
FROM time_slots ts
CROSS JOIN AGENT AG
LEFT JOIN AGENT_HISTORY AH
ON AH.AGENTID = AG.ID
AND EVENT_DATE BETWEEN START_DATE AND END_DATE
LEFT JOIN CPU_HISTORY CH
ON AH.EVENT_ID = CH.EVENT_ID
WHERE AG.NAME = 'myAgent'
GROUP BY START_DATE
ORDER BY 1;
This ensures you get the full 24 rows (one for each timeslot).
Change start_date to to_char(start_date, 'hh24:mi') both in select and group by clauses.

Oracle - display all within next 12 months

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 :)

Previous Month based on SYSDATE

I have a table called PRTIME with a date field called TR_DATE. Based on the SYSDATE, I need to query the PRTIME table for the month prior to SYSDATE.
In SQL Server I would do the following:
select * from PRTIME
WHERE datepart(month,TR_DATE) = datepart(month,dateadd(month,-1,current_timestamp))
and datepart(year,TR_DATE) = datepart(year,dateadd(month,-1,current_timestamp))
How would I do this in Oracle?
I'd just do
WHERE tr_date >= trunc( add_months( sysdate, -1 ), 'MM' )
AND tr_date < trunc( sysdate, 'MM' )

Resources