How to generate each day of backlog for a ticket - oracle

Hi I'm trying to create a procedure for calculating the backlog for each day.
For example: I have a ticket with ticket_submitdate on 12-sep-2015 and resolved_date on 15-sep-2015 in one table. This ticket should come as a backlog in the backlog_table because it was not resolved on the same day as the ticket_submitdate.
I have another column date_col in the backlog_table where the date on which the ticket was a backlog is displayed,i.e, it should be there in the ticket_backlog table for dates 13-sep-2015 and 14-sep-2015 and the date_col column should have this ticket for both these dates.
Please help.
Thanks in advance.

Here is some test data:
create table backlog (ticket_no number, submit_date date, resolved_date date);
insert into backlog values (100, date '2015-09-12', date '2015-09-15');
insert into backlog values (200, date '2015-09-12', date '2015-09-14');
insert into backlog values (300, date '2015-09-13', date '2015-09-15');
insert into backlog values (400, date '2015-09-13', date '2015-09-16');
insert into backlog values (500, date '2015-09-13', date '2015-09-13');
This query generates a list of dates which spans the range of BACKLOG records, and joins them to the BACKLOG.
with dt as ( select min(submit_date) as st_dt
, greatest(max(resolved_date), max(submit_date)) as end_dt
from backlog)
, dt_range as ( select st_dt + (level-1) as date_col
from dt
connect by level <= ( end_dt - st_dt ))
select b.ticket_no
, d.date_col
from backlog b
cross join dt_range d
where d.date_col between b.submit_date and b.resolved_date
and b.submit_date != b.resolved_date
order by b.ticket_no
, d.date_col
/
Therefore it produces a list of TICKET_NOs with all the dates when they are live:
TICKET_NO DATE_COL
---------- ---------
100 12-SEP-15
100 13-SEP-15
100 14-SEP-15
100 15-SEP-15
200 12-SEP-15
200 13-SEP-15
200 14-SEP-15
300 13-SEP-15
300 14-SEP-15
300 15-SEP-15
400 13-SEP-15
400 14-SEP-15
400 15-SEP-15
14 rows selected.
SQL>
The result set does not include ticket #500 because it was resolved on the day of submission. You will probably need to tweak the filters to fit your actual business rules.

I m not sure I understood your question, if you are looking for all dates between two date range then you can use below query -
select trunc(date_col2+lv) from
(select level lv from dual connect by level < (date_col1-date_col2-1) )
order by 1

Related

Oracle SQL Developer get table rows older than n months

In Oracle SQL Developer, I have a table called t1 who have two columns col1 defined as NUMBER(19,0) and col2 defined as TIMESTAMP(3).
I have these rows
col1 col2
1 03/01/22 12:00:00,000000000
2 03/01/22 13:00:00,000000000
3 26/11/21 10:27:11,750000000
4 26/11/21 10:27:59,606000000
5 16/12/21 11:47:04,105000000
6 16/12/21 12:29:27,101000000
My sysdate looks like this:
select sysdate from dual;
SYSDATE
03/03/22
I want to create a stored procedure (SP) which will delete rows older than 2 months and displayed message n rows are deleted
But when i execute this statement
select * from t1 where to_date(TRUNC(col2), 'DD/MM/YY') < add_months(sysdate, -2);
I don't get the first 2 rows of my t1 table. I get more than 2 rows
1 03/01/22 12:00:00,000000000
2 03/01/22 13:00:00,000000000
How can i get these rows and deleted it please ?
In Oracle, a DATE data type is a binary data type consisting of 7 bytes (century, year-of-century, month, day, hour, minute and second). It ALWAYS has all of those components and it is NEVER stored with a particular formatting (such as DD/MM/RR).
Your client application (i.e. SQL Developer) may choose to DISPLAY the binary DATE value in a human readable manner by formatting it as DD/MM/RR but that is a function of the client application you are using and not the database.
When you show the entire value:
SELECT TO_CHAR(ADD_MONTHS(sysdate, -2), 'YYYY-MM-DD HH24:MI:SS') AS dt FROM DUAL;
Then it outputs (depending on time zone):
DT
2022-01-03 10:11:28
If you compare that to your values then you can see that 2022-01-03 12:00:00 is not "more than 2 months ago" so it will not be matched.
What you appear to want is not "more than 2 months ago" but "equal to or more than 2 months, ignoring the time component, ago"; which you can get using:
SELECT *
FROM t1
WHERE col2 < add_months(TRUNC(sysdate), -2) + INTERVAL '1' DAY;
or
SELECT *
FROM t1
WHERE TRUNC(col2) <= add_months(TRUNC(sysdate), -2);
(Note: the first query would use an index on col2 but the second query would not; it would require a function-based index on TRUNC(col2) instead.)
Also, don't use TO_DATE on a column that is already a DATE or TIMESTAMP data type. TO_DATE takes a string as the first argument and not a DATE or TIMESTAMP so Oracle will perform an implicit conversion using TO_CHAR and if the format models do not match then you will introduce errors (and since any user can set their own date format in their session parameters at any time then you may get errors for one user that are not present for other users and is very hard to debug).
db<>fiddle here
Perhaps just:
select *
from t1
where col2 < add_months(sysdate, -2);

Finding all matching rows in a 30 day time window

I have a situation where I have a row in a table for each time a customer visits. What I'm trying to do is find those customers who have visited within any given 30 day window and select those visits.
EX: The main focus is just going to be on three rows in the Table: ROW_ID, CUSTOMER_ID, VISIT_DATE (in the date format).
What I'm trying to get is when a customer has visited multiple times within a 30 day span. EX: CUSTOMER_ID #5 visits on the 10/8/2019 and again on 11/1/2019, I would want to see both rows
We could try using exists logic to handle the requirement:
SELECT ROW_ID, CUSTOMER_ID, VISIT_DATE
FROM yourTable t1
WHERE EXISTS (SELECT 1 FROM yourTable t2
WHERE t2.CUSTOMER_ID = t2.CUSTOMER_ID AND
t2.ROW_ID <> t1.ROW_ID AND
ABS(t2.VISIT_DATE - t1.VISIT_DATE) <= 30);
The logic behind the above query reads cleanly as return any customer record where there another record for the same customer such that the two (different) records are within 30 days of each other.

Logic for change in one column value in pl/sql

I have an assignmentes table asg_tab with effective start date and effective end date columns which track on which dates which change was made.
asg_tab
eff_start_date eff_End_date PER_ASG_ATTRIBUTE2 job name pos name
01-Jan-2015 03-feb-2015 Ck Bonus Retail Mgr
04-Feb-2015 20-Feb-2015 UK Bonus Sales Mgr
21-Feb-2015 28-Nov-2015 UK Bonus Sales Snr. Mgr
Now I have to calculate the number of days for which PER_ASG_ATTRIBUTE2 is UK Bonus. For example in the above case it will be days between 04-Feb-2015 to 28-Nov-2015.
I have written the logic below, which is fetching values from cursor.
cursor cur_asg
is
select
eff_start_date,
eff_End_date,
PER_ASG_ATTRIBUTE2,
job_name,
pos_name
from
asg_tab
Logic I have built :
START_DT ='01-Jan-2015'
END_DT ='31-Dec-2015'
IF PER_ASG_ATTRIBUTE2 LIKE '%UK Bonus%' THEN
(
l_new_ATTR = PER_ASG_ATTRIBUTE2
l_effective_date = i.eff_start_date
IF (l_new_ATTR <> l_old_ATTR) AND (l_effective_date >= START_DT ) AND (l_effective_date =< END_DT)
THEN
(
l_days=eff_end_date -eff_start_date
)
l_old_ATTR = l_new_ATTR
)
The issue which is coming up is that from this condition: IF (l_new_ATTR <> l_old_ATTR) AND (l_effective_date >= START_DT ) AND (l_effective_date =< END_DT)
This condition will pick the 2nd row where the PER_ASG_ATTRIBUTE2 changed from Ck Bonus to UK Bonus but when the pos name changes the 3rd row is generated.
Even though the PER_ASG_ATTRIBUTE2 is still UK Bonus this will not be filtered in the if condition.
What more can I add to this condition ?

How to replace start date and end date for multiple row data with the maximum and minimum of date in pl/sql

I have a multiple rows data with unique start date and end date combination.
I want to replace the start date with the minimum of all the start dates
and End date with maximum of all the end dates.
Example:
id start Date end Date
1005 09/01/2000 05/31/2001
1005 09/05/2000 05/23/2001
100775 03/15/2005 04/30/2005
100775 03/25/2005 04/22/2005
3273 09/01/2003 12/31/2004
3273 09/11/2003 12/11/2004
Now I want the output to look like:
id start Date end date
1005 09/01/2000 05/31/2001
1005 09/01/2000 05/31/2001
100775 03/15/2005 04/30/2005
100775 03/15/2005 04/30/2005
3273 09/01/2003 12/31/2004
3273 09/01/2003 12/31/2004
I have tried doing this with max and min functions but that doesn't work since I want this to be only one query for using it in oracle report builder.
You can use just use min and max function to get your desired output:
select
id,
min(start_date) OVER (PARTITION BY id) start_date,
max(end_date) OVER (PARTITION BY id) end_date
FROM table1;
SQL Fiddle Demo
Another way of doing this,
UPDATE T1 SET StartDate = MinStartDate, EndDate = MaxEndDate
FROM (
Select id, min(StartDate) as 'MinStartDate',
Max(EndDate) as 'MaxEndDate'
from T1
Group by id
) AS T2
WHERE T1.id = T2.id;

"BETWEEN" SQL Keyword for Oracle Dates -- Getting an error in Oracle

I have dates in this format in my database "01-APR-12" and the column is a DATE type.
My SQL statement looks like this:
SELECT DISTINCT c.customerno, c.lname, c.fname
FROM customer c, sales s
WHERE c.customerno = s.customerno AND s.salestype = 1
AND (s.salesdate BETWEEN '01-APR-12' AND '31-APR-12');
When I try to do it that way, I get this error -- ORA-01839: date not valid for month specified.
Can I even use the BETWEEN keyword with how the date is setup in the database?
If not, is there another way I can get the output of data that is in that date range without having to fix the data in the database?
Thanks!
April has 30 days not 31.
Change
SELECT DISTINCT c.customerno, c.lname, c.fname
FROM customer c, sales s
WHERE c.customerno = s.customerno AND s.salestype = 1
AND (s.salesdate BETWEEN '01-APR-12' AND '31-APR-12');
to
SELECT DISTINCT c.customerno, c.lname, c.fname
FROM customer c, sales s
WHERE c.customerno = s.customerno AND s.salestype = 1
AND (s.salesdate BETWEEN '01-APR-12' AND '30-APR-12');
and you should be good to go.
In case the dates you are checking for range from 1st day of a month to the last day of a month then you may modify the query to avoid the case where you have to explicitly check the LAST day of the month
SELECT DISTINCT c.customerno, c.lname, c.fname
FROM customer c, sales s
WHERE c.customerno = s.customerno
AND s.salestype = 1 AND (s.salesdate BETWEEN '01-APR-12' AND LAST_DAY(TO_DATE('APR-12', 'MON-YY'));
The LAST_DAY function will provide the last day of the month.
The other answers are missing out on something important and will not return the correct results. Dates have date and time components. If your salesdate column is in fact a date that includes time, you will miss out on any sales that happened on April 30 unless they occurred exactly at midnight.
Here's an example:
create table date_temp (temp date);
insert into date_temp values(to_date('01-APR-2014 15:12:00', 'DD-MON-YYYY HH24:MI:SS'));
insert into date_temp values(to_date('30-APR-2014 15:12:00', 'DD-MON-YYYY HH24:MI:SS'));
table DATE_TEMP created.
1 rows inserted.
1 rows inserted.
select * from date_temp where temp between '01-APR-2014' and '30-APR-2014';
Query Result: 01-APR-14
If you want to get all records from April that includes those with time-components in the date fields, you should use the first day of the next month as the second side of the between clause:
select * from date_temp where temp between '01-APR-2014' and '01-MAY-2014';
01-APR-14
30-APR-14

Resources