How do I subtract multiple dates? - sql

An image of the Discharge date and admission date in which i am supposed to subtract as (discharge date – admitted
date) +1 .

As you said - subtract and sum. Sample data in lines #1 - 5, query begins at line #6.
SQL> with test (who, admission_date, discharge_date) as
2 (select 'Leslie', date '2010-09-13', date '2010-09-25' from dual union all
3 select 'Leslie', date '2014-09-03', date '2014-09-21' from dual union all
4 select 'Leslie', date '2015-12-03', date '2015-12-14' from dual
5 )
6 select who, sum(discharge_date - admission_date + 1) total_days
7 from test
8 group by who;
WHO TOTAL_DAYS
------ ----------
Leslie 44
SQL>

Related

How to sum (by year) the substraction of two columns showing a running sum of it in the same record [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 months ago.
Improve this question
With data like this
-- Sample data:
CREATE TABLE IN_OUT_TABLE (DATE_OF Date, INPUT_CASES Number(3), OUTPUT_CASES Number(3));
--
Insert Into IN_OUT_TABLE Values(To_Date('01-AUG-2019', 'dd-MON-yyyy'), 2, 1);
Insert Into IN_OUT_TABLE Values(To_Date('01-SEP-2019', 'dd-MON-yyyy'), 3, 1);
Insert Into IN_OUT_TABLE Values(To_Date('01-MAY-2020', 'dd-MON-yyyy'), 3, 3);
Insert Into IN_OUT_TABLE Values(To_Date('01-MAR-2020', 'dd-MON-yyyy'), 7, 2);
Insert Into IN_OUT_TABLE Values(To_Date('01-APR-2021', 'dd-MON-yyyy'), 3, 1);
Insert Into IN_OUT_TABLE Values(To_Date('01-JUL-2021', 'dd-MON-yyyy'), 4, 2);
Need to select the sum of the diferencies between input and output cases
(INPUT_CASES - OUTPUT_CASES) grouped by year of the DATE_OF.
The result should be shown as PERIOD for a particular year. Beside, there should be a CUMULATIVE column showing running sum of PERIOD values.
So,
PERIOD = INPUT_CASES - OUTPUT_CASES - this should be summed by year
CUMULATIVE = running sum of PERIOD - year by year (ordered by year)
Having that in mind is it posible to construct a select command something like this
SELECT DATE, PERIOD, SUM(PERIOD) OVER(ORDER BY DATE)
FROM ( SELECT EXTRACT(YEAR FROM DATE) as DATE, SUM(PERIOD) as PERIOD
FROM IN_OUT_TABLE
GROUP BY EXTRACT(YEAR FROM DATE))
... ... and get the expected result?
Expected result would be:
-- YEAR PERIOD CUMULATIVE
-- ---- ----------- -------------
-- 2019 3 3
-- 2020 5 8
-- 2021 4 12
Thanks, ...
Is this maybe the answer that you are looking for?...
WITH
tbl AS
(
Select To_Date('01-AUG-2019', 'dd-MON-yyyy') "DT", 2 "INP", 1 "OUTP" From DUAL UNION ALL
Select To_Date('01-SEP-2019', 'dd-MON-yyyy') "DT", 3 "INP", 1 "OUTP" From DUAL UNION ALL
Select To_Date('01-MAY-2020', 'dd-MON-yyyy') "DT", 3 "INP", 3 "OUTP" From DUAL UNION ALL
Select To_Date('01-MAR-2020', 'dd-MON-yyyy') "DT", 7 "INP", 2 "OUTP" From DUAL UNION ALL
Select To_Date('01-APR-2021', 'dd-MON-yyyy') "DT", 3 "INP", 1 "OUTP" From DUAL UNION ALL
Select To_Date('01-JUL-2021', 'dd-MON-yyyy') "DT", 4 "INP", 2 "OUTP" From DUAL
)
SELECT
YR,
PERIOD,
Sum(PERIOD) OVER(Order By YR ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) "CUMUL"
FROM
(
SELECT DISTINCT
EXTRACT(YEAR FROM DT) "YR",
Sum(INP- OUTP) OVER(Partition By EXTRACT(YEAR FROM DT) Order By EXTRACT(YEAR FROM DT)) "PERIOD"
FROM
tbl
ORDER BY
EXTRACT(YEAR FROM DT)
)
--
-- R e s u l t
--
-- YR PERIOD CUMUL
-- ---------- ---------- ----------
-- 2019 3 3
-- 2020 5 8
-- 2021 4 12
Something like this:
with
tbl (date_, input, output) as (
select date '2019-08-01', 2, 1 from dual union all
select date '2019-09-01', 3, 1 from dual union all
select date '2020-05-01', 3, 3 from dual union all
select date '2020-03-01', 7, 2 from dual union all
select date '2021-04-01', 3, 1 from dual union all
select date '2021-07-01', 4, 2 from dual
)
select extract(year from trunc(date_, 'year')) as year_,
nvl(sum(input), 0) - nvl(sum(output), 0) as period,
sum(nvl(sum(input), 0) - nvl(sum(output), 0))
over (order by trunc(date_, 'year')) as cumulative
from tbl
group by trunc(date_, 'year')
order by year_
;
YEAR_ PERIOD CUMULATIVE
---------- ---------- ----------
2019 3 3
2020 5 8
2021 4 12
The with clause is for testing purposes only, it is not part of the query. To test the query on your actual data, remove the with clause, and use your actual table and column names (I used tbl for the table, and date_, input and output for the columns - note that date is a reserved keyword, which should not be used as column name).
In the query I truncate each date to the beginning of the year, and I group by the result. If there is an index on the date_ column, this may be more efficient than extracting the year with the extract function. (Worth trying both ways on your actual data.) In any case, you should need only one pass over the base data.
I wrapped the sums of input and output within nvl(..., 0) - that way if in a year all inputs (or all outputs) are null, the sum will be treated as 0, instead of messing up the difference (the period result).

Finding overlapping and calculation of min and max dates with in overlap in oracle [duplicate]

This question already has answers here:
print start and end date in one row for continous or overlaping date ranges in oracle SQL
(2 answers)
Closed 2 years ago.
How can we find the between the overlap lap b/w the dates .
overlap means when start date and end date are within same range
for below example row 1 has no over lap.
Row 2to 5 can be considered as one set of over lap as there start date and end are over lap with themselves
Row 6 & 7 can be considered as one set of over lap
for eg. row 6 & 7 --> start date of row 7 is in same range with respect to end date of row 6
so it becomes an overlap
Once overlap is found then and need to find out min(start date) and max(end date) and
want to assign a unique id to each overlap and in the S.NO column should show which rows are overlapped .Below is the I/p and O/p
I/p
You can do it simply and efficiently using MATCH_RECOGNIZE to perform a row-by-row comparison and aggregation:
SELECT id, start_date, end_date
FROM table_name
MATCH_RECOGNIZE (
PARTITION BY id
ORDER BY start_date
MEASURES FIRST(start_date) AS start_date,
MAX(end_date) AS end_date
PATTERN ( overlapping_dates* last_date )
DEFINE overlapping_dates as MAX(end_date) >= NEXT(start_date)
);
Which, for the sample data:
CREATE TABLE table_name ( sno, id, start_date, end_date ) AS
SELECT 1, 1, DATE '2019-10-11', DATE '2019-10-11' FROM DUAL UNION ALL
SELECT 2, 1, DATE '2019-11-04', DATE '2019-12-11' FROM DUAL UNION ALL
SELECT 3, 1, DATE '2019-11-05', DATE '2019-11-10' FROM DUAL UNION ALL
SELECT 4, 1, DATE '2019-11-06', DATE '2019-11-10' FROM DUAL UNION ALL
SELECT 5, 1, DATE '2019-11-20', DATE '2019-12-20' FROM DUAL UNION ALL
SELECT 6, 1, DATE '2020-01-01', DATE '2020-01-20' FROM DUAL UNION ALL
SELECT 7, 1, DATE '2020-01-15', DATE '2020-03-25' FROM DUAL;
Outputs:
ID | START_DATE | END_DATE
-: | :------------------ | :------------------
1 | 2019-10-11 00:00:00 | 2019-10-11 00:00:00
1 | 2019-11-04 00:00:00 | 2019-12-20 00:00:00
1 | 2020-01-01 00:00:00 | 2020-03-25 00:00:00
db<>fiddle here

Date and quarter SQL ORACLE

I am currently working on oracle sql and have some issues managing dates and quarters.
The first thing I try to do is given a quarter and a year I would like to know the number of days of the quarter. For example, quarter 1 in 2013 had 90 days but in 2012 had 91 days.
The second thing I would like to do is convert a date dd/qq/yyyy to a date
dd/mm/yyyy.
For instance, 60/2/2013 gives 30/5/2013. I am a beginner in Oracle so any help or function names will be highly appreciated.
Thanks
this gives the number of days in the current quarter, playing around with the add_months should allow you to find the length of other quarters
select (add_months(trunc(sysdate,'q'),3) - 1) - trunc(sysdate,'q')
from dual;
For your first question, hopefully this will give you some idea of what to do:
with sample_data as (select 2012 yr, 1 quarter from dual union all
select 2012 yr, 2 quarter from dual union all
select 2012 yr, 3 quarter from dual union all
select 2012 yr, 4 quarter from dual union all
select 2013 yr, 1 quarter from dual union all
select 2013 yr, 2 quarter from dual)
---- end of mimicking a table called "sample_data"; see query below:
select yr,
quarter,
add_months(to_date('01/01/'||yr, 'dd/mm/yyyy'), (quarter - 1)*3) qtr_st,
add_months(to_date('01/01/'||yr, 'dd/mm/yyyy'), quarter * 3) - 1 qtr_end,
add_months(to_date('01/01/'||yr, 'dd/mm/yyyy'), quarter * 3) - add_months(to_date('01/01/'||yr, 'dd/mm/yyyy'), (quarter - 1)*3) diff
from sample_data;
YR QUARTER QTR_ST QTR_END DIFF
---------- ---------- ---------- ---------- ----------
2012 1 01/01/2012 31/03/2012 91
2012 2 01/04/2012 30/06/2012 91
2012 3 01/07/2012 30/09/2012 92
2012 4 01/10/2012 31/12/2012 92
2013 1 01/01/2013 31/03/2013 90
2013 2 01/04/2013 30/06/2013 91
N.B. Because you're including the day of the start_date in the count, the difference is effectively how many days between the 1st of the quarter and the 1st of the next quarter, or qtr_end - qtr_st + 1 from my query above.
For your second question, here's one way:
with sample_data as (select '60/2/2013' dy_qtr_fmt from dual union all
select '60/02/2013' dy_qtr_fmt from dual union all
select '01/1/2013' dy_qtr_fmt from dual union all
select '1/1/2013' dy_qtr_fmt from dual)
---- end of mimicking a table called "sample_data"; see query below:
select dy_qtr_fmt,
add_months(year_st, (qtr-1)*3) + num_days_in_qtr - 1 dt
from (select dy_qtr_fmt,
to_date('01/01/'||substr(dy_qtr_fmt, -4), 'dd/mm/yyyy') year_st,
to_number(substr(dy_qtr_fmt, instr(dy_qtr_fmt, '/', 1, 1) + 1, instr(dy_qtr_fmt, '/', 1, 2) - instr(dy_qtr_fmt, '/', 1, 1) -1)) qtr,
to_number(substr(dy_qtr_fmt, 1, instr(dy_qtr_fmt, '/', 1, 1) - 1)) num_days_in_qtr
from sample_data);
DY_QTR_FMT DT
---------- ----------
60/2/2013 30/05/2013
60/02/2013 30/05/2013
01/1/2013 01/01/2013
1/1/2013 01/01/2013

Number of days in a month

I have a monthly amount that I need to spread equally over the number of days in the month. The data looks like this:
Month Value
----------- ---------------
01-Jan-2012 100000
01-Feb-2012 121002
01-Mar-2012 123123
01-Apr-2012 118239
I have to spread the Jan amount over 31 days, the Feb amount over 29 days and the March amount over 31 days.
How can I use PL/SQL to find out how many days there are in the month given in the month column?
SELECT CAST(to_char(LAST_DAY(date_column),'dd') AS INT)
FROM table1
Don't use to_char() and stuff when doing arithmetics with dates.
Strings are strings and dates are dates. Please respect the data types and use this instead:
1+trunc(last_day(date_column))-trunc(date_column,'MM')
Indeed, this is correct. It computes the difference between the value of the last day of the month and the value of the first (which is obviously always 1 and therefore we need to add this 1 again).
You must not forget to use the trunc() function if your date columns contains time, because last_day() preserves the time component.
SELECT EXTRACT(DAY FROM LAST_DAY(SYSDATE)) num_of_days FROM dual;
/
SELECT SYSDATE, TO_CHAR(LAST_DAY(SYSDATE), 'DD') num_of_days FROM dual
/
-- Days left in a month --
SELECT SYSDATE, LAST_DAY(SYSDATE) "Last", LAST_DAY(SYSDATE) - SYSDATE "Days left"
FROM DUAL
/
You can add a month and subtract the two dates
SQL> ed
Wrote file afiedt.buf
1 with x as (
2 select date '2012-01-01' dt from dual union all
3 select date '2012-02-01' from dual union all
4 select date '2012-03-01' from dual union all
5 select date '2012-01-31' from dual
6 )
7 select dt, add_months(trunc(dt,'MM'),1) - trunc(dt,'MM')
8* from x
SQL> /
DT ADD_MONTHS(TRUNC(DT,'MM'),1)-TRUNC(DT,'MM')
--------- -------------------------------------------
01-JAN-12 31
01-FEB-12 29
01-MAR-12 31
31-JAN-12 31
select add_months(my_date, 1)-my_date from dual;
SELECT TO_CHAR(LAST_DAY(SYSDATE), 'fmday-mon-rr dd') as LastDayOfMonth
FROM dual;
Use the following Oracle query:
select to_number(to_char(last_day(sysdate),'dd')) TotalDays from dual
Date_Parameter='01-Oct-2017'
select to_number(to_char(last_day('Date_Parameter'),'dd')) TotalDays from dual

oracle count based on month

I am attempting to write Oracle SQL.
I am looking for solution something similar. Please find below data I have
start_date end_date customer
01-01-2012 31-06-2012 a
01-01-2012 31-01-2012 b
01-02-2012 31-03-2012 c
I want the count of customer in that date period. My result should look like below
Month : Customer Count
JAN-12 : 2
FEB-12 : 2
MAR-12 : 2
APR-12 : 1
MAY-12 : 1
JUN-12 : 1
One option would be to generate the months separately in another query and join that to your data table (note that I'm assuming that you intended customer A to have an end-date of June 30, 2012 since there is no June 31).
SQL> ed
Wrote file afiedt.buf
1 with mnths as(
2 select add_months( date '2012-01-01', level - 1 ) mnth
3 from dual
4 connect by level <= 6 ),
5 data as (
6 select date '2012-01-01' start_date, date '2012-06-30' end_date, 'a' customer from dual union all
7 select date '2012-01-01', date '2012-01-31', 'b' from dual union all
8 select date '2012-02-01', date '2012-03-31', 'c' from dual
9 )
10 select mnths.mnth, count(*)
11 from data,
12 mnths
13 where mnths.mnth between data.start_date and data.end_date
14 group by mnths.mnth
15* order by mnths.mnth
SQL> /
MNTH COUNT(*)
--------- ----------
01-JAN-12 2
01-FEB-12 2
01-MAR-12 2
01-APR-12 1
01-MAY-12 1
01-JUN-12 1
6 rows selected.
WITH TMP(monthyear,start_date,end_date,customer) AS (
select LAST_DAY(start_date),
CAST(ADD_MONTHS(start_date, 1) AS DATE),
end_date,
customer
from data
union all
select LAST_DAY(start_date),
CAST(ADD_MONTHS(start_date, 1) AS DATE),
end_date,
customer
from TMP
where LAST_DAY(end_date) >= LAST_DAY(start_date)
)
SELECT TO_CHAR(MonthYear, 'MON-YY') TheMonth,
Count(Customer) Customers
FROM TMP
GROUP BY MonthYear
ORDER BY MonthYear;
SQLFiddle