Converting date range to multiple period - sql

I have table like below
ID StartDate EndDate
1 15-MAR-2009 8-DEC-2011
2 14-JAN-2010 18-FEB-2013
I need output something like this -
ID StartDate EndDate
1 15-MAR-2009 31-DEC-2009
1 1-JAN-2010 31-DEC-2010
1 1-JAN-2011 8-Dec-2011
2 14-JAN-2010 31-DEC-2010
2 1-JAN-2011 31-DEC-2011
2 1-JAN-2012 31-DEC-2012
2 1-JAN-2013 18-FEB-2013
I have 9i oracle as database, I would perfer to do this with informatica but seems difficult to find solution there, cant create a procedure so need sql query. If anyone can provide in informatica 8.6 then that would be even great.
Edited :-
Create table test_range
(Sr_No number,
start_date date,
end_date date)
create table yr_range
(years date);
Insert statements :-
insert into test_range values (1,'15-MAR-2009','8-DEC-2011');
insert into test_range values (2,'14-JAN-2010','18-FEB-2013');
insert into yr_range values ('31-Dec-2005');
insert into yr_range values ('31-Dec-2006');
insert into yr_range values ('31-Dec-2007');
insert into yr_range values ('31-Dec-2008');
insert into yr_range values ('31-Dec-2009');
insert into yr_range values ('31-Dec-2010');
insert into yr_range values ('31-Dec-2011');
insert into yr_range values ('31-Dec-2012');
insert into yr_range values ('31-Dec-2013');
As suggested in one of the answer, I have created another table to get desired output, is it possible using one table only(i.e. test_range)? I m want exploer all the options before finalizing the one.

If you had something like a years dimension, where each row represented a year, then you would join with it based on whether the year falls within the range. This will give you the number of rows you need, and then for each row you conditionally output the start/end ranges. This should also handle cases where your range is less than a year and thus would not be split up.
y.Year is assumed to be an integer.
See working example here: http://sqlfiddle.com/#!4/d4589/13/11
Create table test_range
(Sr_No number,
StartDate date,
EndDate date);
create table yr_range
(years number);
insert into test_range values (1,'15-MAR-2009','8-DEC-2011');
insert into test_range values (2,'14-JAN-2010','18-FEB-2013');
insert into yr_range values ('2005');
insert into yr_range values ('2006');
insert into yr_range values ('2007');
insert into yr_range values ('2008');
insert into yr_range values ('2009');
insert into yr_range values ('2010');
insert into yr_range values ('2011');
insert into yr_range values ('2012');
insert into yr_range values ('2013');
select
r.Sr_No,
CASE
When to_char( r.StartDate, 'yyyy') = y.years Then r.StartDate
Else to_date( y.years || '/01/01', 'yyyy/mm/dd')
END as StartDate,
CASE
When to_char( r.EndDate , 'yyyy') = y.years Then r.EndDate
Else to_date( y.years || '/12/31', 'yyyy/mm/dd')
END as EndDate
from test_range r, yr_range y
where
to_char( r.StartDate, 'yyyy') <= y.years
AND to_char( r.EndDate, 'yyyy') >= y.years;
You could also generate your years sequence using some of these techniques:
ORACLE SQL:Get all integers between two numbers

Related

How to transform following table to desired table

I have a table with the following structure:
ID
StartDate (YY-MM-DD)
EndDate (YY-MM-DD)
1
20-07-13
21-05-12
2
15-04-12
27-01-01
3
14-01-30
18-12-30
4
18-02-21
5
20-12-12
20-12-15
6
20-11-11
7
19-10-22
20-08-10
8
17-09-01
19-04-15
9
18-06-27
21-08-19
9
19-08-17
I would like to write a query that creates an output with the following structure:
Count the IDs which are active during each period. For example ID: 1 was active between 13. July 2020 and 12. May 2021, so it should be added to the count during 202007 and 202105.
As long as there is now EndDate, the ID should be added to the count till the present period.
COUNT_ID
YYYYMM
150
201601
200
201602
180
201603
...
...
...
...
...
...
I struggle to find a way to calculate the count of active IDs for each period, I believe there is an simple way to do that but unfortunately I donĀ“t know.
Any help/tip/hint is much appreciated!
Best regards,
Frederik
If I'm understanding correctly, you will want to:
Generate a table of month-start-and-end ranges, between a start date (June 2016) and present
Then, for each month, examine how many of your records' start and end dates contain any days that fall within that month
CREATE TABLE #temp_ids (id INT,
id_start DATE,
id_end DATE);
INSERT INTO #temp_ids (id, id_start, id_end) Values (1,'20200713','20210512');
INSERT INTO #temp_ids (id, id_start, id_end) Values (2,'20150412','20270101');
INSERT INTO #temp_ids (id, id_start, id_end) Values (3,'20140130','20181230');
INSERT INTO #temp_ids (id, id_start) Values (4,'20180221');
INSERT INTO #temp_ids (id, id_start, id_end) Values (5,'20201212','20201215');
INSERT INTO #temp_ids (id, id_start) Values (6,'20201111');
INSERT INTO #temp_ids (id, id_start, id_end) Values (7,'20191022','20200810');
INSERT INTO #temp_ids (id, id_start, id_end) Values (8,'20170901','20190415');
INSERT INTO #temp_ids (id, id_start, id_end) Values (9,'20180627','20210809');
INSERT INTO #temp_ids (id, id_start) Values (10,'20190817');
DECLARE #windowStart DATE = '20160101',
#windowEnd DATE = GETDATE();
;WITH report_dates AS (--This is a convenient piece of code to generate a table of dates between two dates
SELECT TOP (DATEDIFF(DAY,
#windowStart,
#windowEnd) + 1
)
DATEADD(DAY,
ROW_NUMBER() OVER(ORDER BY a.object_id) - 1,
#windowStart
) AS report_date
FROM sys.all_objects AS a
CROSS JOIN sys.all_objects AS b
),
month_windows AS (--Filter the dates we just generated to only month-start, and add month-end
SELECT report_date AS month_start,
EOMONTH(report_date) AS month_end
FROM report_dates
WHERE DATEPART(DAY, report_date) = 1
)
SELECT --Count the number of records which overlap with the month range
DISTINCT month_start,
month_end,
COUNT(id) AS count_id
FROM #temp_ids AS ti
JOIN month_windows mw ON ((ti.id_start <= mw.month_start AND ti.id_end >= mw.month_start)
OR (ti.id_start >= mw.month_start AND ti.id_start <= mw.month_end)
)
WHERE id_end IS NOT NULL
GROUP BY month_start,
month_end

How to INSERT the continuous Date in HANA with SQL statement?

I have to insert the data like as below from 01-01-2018 to 31-12-2018.
insert into "schema"."tablename" (FISCAL_DATE,FISCAL_DT,REGION_CD,FISCAL_REGION_CD,FISCAL_DATE1,NEW_REGION_CD) values ('2018-01-01', '2018-01-01','EMEA','EUR','01/01/2018', 'EURO');
insert into "schema"."tablename" (FISCAL_DATE,FISCAL_DT,REGION_CD,FISCAL_REGION_CD,FISCAL_DATE1,NEW_REGION_CD) values ('2018-01-01', '2018-01-01','EMEA','EUR','01/01/2018', 'EURO');
insert into "schema"."tablename" (FISCAL_DATE,FISCAL_DT,REGION_CD,FISCAL_REGION_CD,FISCAL_DATE1,NEW_REGION_CD) values ('2018-01-01', '2018-01-01','EMEA','EUR','01/01/2018', 'EURO');
insert into "schema"."tablename" (FISCAL_DATE,FISCAL_DT,REGION_CD,FISCAL_REGION_CD,FISCAL_DATE1,NEW_REGION_CD) values ('2018-01-01', '2018-01-01','EMEA','EUR','01/01/2018', 'EURO');
...
insert into "schema"."tablename" (FISCAL_DATE,FISCAL_DT,REGION_CD,FISCAL_REGION_CD,FISCAL_DATE1,NEW_REGION_CD) values ('2018-12-31', '2018-12-31','EMEA','EUR','12/31/2018', 'EURO');
Is there any alternative SQL statements to achieve this or else need to go with manually update the dates one by one.
Please share your inputs/suggestions.
If I understood you correctly, you want to insert multiple records (day by day) with dates from 2018-01-01 to 2018-12-31.
You can achieve this using WHILE statement.
DO
BEGIN
DECLARE INPUT_DATE date := '2018-01-01';
WHILE INPUT_DATE <= '2018-12-31' DO
INSERT INTO "schema"."tablename" (FISCAL_DATE,FISCAL_DT,REGION_CD,FISCAL_REGION_CD,FISCAL_DATE1,NEW_REGION_CD) values (:INPUT_DATE, :INPUT_DATE,'EMEA','EUR',:INPUT_DATE, 'EURO');
INPUT_DATE = ADD_DAYS(:INPUT_DATE,1);
END WHILE;
END
You can also use a SQL dates table on HANA database and it is very easy to create using SQLScript.
Please check following example (please replace table name and column names according to your model)
do
begin
declare date_start date := '01.01.2018';
declare date_end date := '31.12.2018';
insert into mySampleTransactionData (tdate)
SELECT generated_period_start
FROM SERIES_GENERATE_DATE('INTERVAL 1 DAY', :date_start, add_days(:date_end,1));
end
I have successfully inserted data with the below Query.
insert into "Schema"."tablename" (select to_nvarchar(gen_date, 'YYYY-MM-DD') as fiscal_date,
to_nvarchar(gen_date, 'YYYY-MM-DD') as fiscal_dt,
'AMR' as region_cd,
'AMR' as fiscal_region_cd,
to_nvarchar(gen_date, 'MM/DD/YYYY') as fiscal_date1,
'AMR' as led_region_cd
from (
select generated_period_start as gen_date from SERIES_GENERATE_DATE ('INTERVAL 1 DAY', '2018-01-01', '2018-12-31')
));
Thank You all for your valuable suggestions!!

have multiple columns need to display column type with other column in rows

input
enter image description here
output
enter image description here
select deptno, replace(title,'d','author),date from employee
for the particular departno I have multiple title and date so i want to display in row wise example
Your data does not match your desired results. Here is what I believe you want:
create table deleteme_tbl(department int, title varchar2(20), mydate date);
insert into deleteme_tbl values( 1,'One', date '2016-01-01');
insert into deleteme_tbl values( 1,'Two', date '2016-04-01');
insert into deleteme_tbl values( 1,'three', date '2016-02-02');
insert into deleteme_tbl values( 2,'five', date '2016-04-04');
insert into deleteme_tbl values( 2,'six', null);
insert into deleteme_tbl values( 2,'seven', null);
commit;
SELECT department
, LISTAGG (title, ',') WITHIN GROUP (ORDER BY title) titles
, LISTAGG (mydate, ',') WITHIN GROUP (ORDER BY mydate) mydates
FROM deleteme_tbl
GROUP BY department;
DEPARTMENT TITLES MYDATES
1 One,Two,three 01-JAN-16,02-FEB-16,01-APR-16
2 five,seven,six 04-APR-16

Reference table from subquery in Oracle

I have simplified my tables but essentially I have a table of accounts that have a cycle_no and end date. This end date is always set to the first of the month but I need to get the real end date by looking in the calendar details table. The real end date is the next date for this cycle_no.
To create the simplified tables and enter a few rows of data:
CREATE TABLE DATA_OWNER.ACCOUNT
(
ACCNO NUMBER(4),
CYCLE_NO NUMBER(4),
ENDDATE DATE
);
CREATE TABLE DATA_OWNER.CALENDAR_DETAILS
(
CALENDAR_DT DATE,
BILL_CYCL_NO NUMBER(4)
);
INSERT INTO calendar_Details
VALUES
('18/DEC/2017',
17);
INSERT INTO calendar_Details
VALUES
('23/DEC/2017',
20);
INSERT INTO calendar_Details
VALUES
('18/JAN/2018',
17);
INSERT INTO calendar_Details
VALUES
('23/JAN/2018',
20);
INSERT INTO calendar_Details
VALUES
('20/FEB/2018',
17);
INSERT INTO calendar_Details
VALUES
('21/FEB/2018',
20);
INSERT INTO account
VALUES
(1, 17, '01/DEC/2107');
INSERT INTO account
VALUES
(2, 20, '01/DEC/2107');
If we run this query though we get "ACC". "ENDDATE": invalid identifier:
SELECT accno, cycle_no, enddate, actual_date
FROM account acc
JOIN
(
SELECT MIN(calendar_dt) actual_date
FROM calendar_details cal
WHERE calendar_dt > acc.enddate
)
ON acc.cycle_no = cal.bill_cycl_no;
Can anyone give us some pointers on the best way to achieve this please?
You cannot refer to outer table references in a subquery in the FROM. Just use a correlated subquery:
SELECT accno, cycle_no, enddate,
(SELECT MIN(cal.calendar_dt) as actual_date
FROM calendar_details cal
WHERE cal.calendar_dt > acc.enddate AND acc.cycle_no = cal.bill_cycl_no
) as actual_date
FROM account acc;

Computing difference in rows for all except consecutive days?

I have a table as follows. I want to compute the difference in dates (in seconds) between consecutive rows according to the following:
If the dates differ by more than a day, then we go ahead and compute the difference
If the dates differ by more than a day and there are consecutive days with the value 84600 for the second date, then I want to first combine the dates before taking a difference
I am currently doing a self-join to handle the first case but am not sure if there is a good way to handle the second case. Any suggestion?
The following also gives an example:
CREATE TABLE #TEMP(Person VARCHAR(100), StartTime Datetime, TotalSeconds INT)
INSERT INTO #TEMP VALUES('A', '2013-02-20', 49800); -- We want to take the difference with the next row in this case
INSERT INTO #TEMP VALUES('A', '2013-02-25', 3000); -- Before taking the difference, I want to first merge the next four rows because 5th March is followed by three days with the value 86400
INSERT INTO #TEMP VALUES('A', '2013-03-05', 2100);
INSERT INTO #TEMP VALUES('A', '2013-03-06', 86400);
INSERT INTO #TEMP VALUES('A', '2013-03-07', 86400);
INSERT INTO #TEMP VALUES('A', '2013-03-08', 86400);
INSERT INTO #TEMP VALUES('A', '2013-03-09', 17100);
INSERT INTO #TEMP VALUES('B', '2012-04-24', 22500);
INSERT INTO #TEMP VALUES('B', '2012-04-26', 600);
INSERT INTO #TEMP VALUES('B', '2012-04-27', 10500);
INSERT INTO #TEMP VALUES('B', '2012-04-29', 41400);
INSERT INTO #TEMP VALUES('B', '2012-05-04', 86100);
SELECT *
FROM #TEMP
DROP TABLE #TEMP
The following handles the second case:
select Person, MIN(StartTime) as StartTime, MAX(StartTime) as maxStartTime
from (SELECT *,
dateadd(d, - ROW_NUMBER() over (partition by person order by StartTime), StartTime) as thegroup
FROM #TEMP t
) t
group by Person, thegroup
It groups all the time periods for a person, with consecutive dates collapsing into a single period (with a begin and end time). The trick is to assign a sequence number, using row_number() and then take the difference from StartTime. This difference is constant for a group of consecutive dates -- hence the outer group by.
You can use a with statement to put this into your query and then get the difference that you desire between consecutive rows.