Date Range Query in Oracle - sql

I have following data
Sr. FromDate ToDate Code
1 1990-01-01 2000-08-31 A
2 2000-09-01 2001-05-31 B
3 2001-06-01 2018-12-31 C
and need to write SQL query to find rows having code for
date range= fromdate 1992-01-01 and ToDate 2000-12-31.
Select *
From Table
Where fromDate <= 1992-01-01
and EndDate >=2000-12-31
not returning proper data.
Any help??
Expected output are first two rows which cover part of date mentioned in query.
One of possible query is:
Select * From table where fromdate <= 19920101
UNION
Select * From table where todate >= 20011231
But some how I don't like it and wanted easier alternative.

Switch the operators
select *
from Table
where fromDate >= '1992-01-01'
and EndDate <= '2000-12-31'

You should migrate the dat to a date object:
Select *
from table
where fromDate >= to_date('1992-01-01','YYYY-MM-DD')
and ...
Look here for valid date formats and syntax:
http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions183.htm

Try reverse filtering, I mean change the dates in filtering:
WITH tab(ID, start_date, end_date, code) AS (
SELECT 1, to_date('1990-01-01', 'YYYY-MM-DD'), to_date('2000-08-31', 'YYYY-MM-DD'), 'A' FROM dual UNION ALL
SELECT 2, to_date('2000-09-01', 'YYYY-MM-DD'), to_date('2001-05-31', 'YYYY-MM-DD'), 'B' FROM dual UNION ALL
SELECT 3, to_date('2001-06-01', 'YYYY-MM-DD'), to_date('2018-12-31', 'YYYY-MM-DD'), 'C' FROM dual)
-----------------
--End of data preparation
-----------------
SELECT *
FROM tab
WHERE end_date >= to_date('1992-01-01', 'YYYY-MM-DD')
AND start_date <= to_date('2000-12-31', 'YYYY-MM-DD');
Output
| ID | START_DATE | END_DATE | CODE |
|----|----------------------------------|-------------------------------|------|
| 1 | January, 01 1990 00:00:00+0000 | August, 31 2000 00:00:00+0000 | A |
| 2 | September, 01 2000 00:00:00+0000 | May, 31 2001 00:00:00+0000 | B |

Based on what you said you have to put an OR. Is it really what you need?
Select *
From Table
Where fromDate <= '1992-01-01'
OR EndDate >='2000-12-31'

Related

Oracle SQL count dates that do not exist between range of dates

I have range of dates:
| date |
| -------- |
| 1/1/2022 |
| 2/1/2022 |
| 3/1/2022 |
| 5/1/2022 |
| 6/1/2022 |
| 7/1/2022 |
| 8/1/2022 |
| 10/1/2022 |
I want to get the dates that are not included between these dates, in this case 4/1 and 9/1, I want the count of these dates, in this case 2, so I want the count of dates that do not exist between a specific range of dates, how can I achieve that?
select (max(date) - min(date) + 1) - count(distinct date)
from table_name
https://dbfiddle.uk/cSKZloYA
(max(date) - min(date) + 1) will give the total number of days in the range.
count(distinct date) will be the number of existing (different) days in the table.
The difference between these is the number of non-existing days.
Note: date is a reserved word, so if it's the actual column name, it has to be delimited as "date". (https://en.wikipedia.org/wiki/List_of_SQL_reserved_words)
You can use the LAG analytic function to find the previous date and then work out the number of days difference and if it is more than 1 then you have that many missing days:
SELECT SUM(missing_dates) AS num_missing
FROM (
SELECT GREATEST("DATE" - LAG("DATE") OVER (ORDER BY "DATE") - 1, 0)
AS missing_dates
FROM table_name
);
Which, for the sample data:
CREATE TABLE table_name ("DATE") AS
SELECT DATE '2020-01-01' FROM DUAL UNION ALL
SELECT DATE '2020-01-02' FROM DUAL UNION ALL
SELECT DATE '2020-01-03' FROM DUAL UNION ALL
SELECT DATE '2020-01-05' FROM DUAL UNION ALL
SELECT DATE '2020-01-06' FROM DUAL UNION ALL
SELECT DATE '2020-01-07' FROM DUAL UNION ALL
SELECT DATE '2020-01-08' FROM DUAL UNION ALL
SELECT DATE '2020-01-10' FROM DUAL;
Outputs:
NUM_MISSING
2
fiddle

Oracle How to list last days of months between 2 dates

I manage to get all the days between 2 dates.
But I would like to get all the lasts day of months between 2 dates (using one request).
All days between 2 dates:
select to_date('01/01/2000','dd/mm/yyyy') + (LEVEL-1) as jour
from dual
connect by level <= to_date('31/12/2050','dd/mm/yyyy')-to_date('01/01/2000','dd/mm/yyyy')
Last day of current month:
select LAST_DAY(sysdate) FROM dual
I don't know how to mix both and get the expected result:
20000131
20000228
20000331
etc...
That would be DISTINCT + LAST_DAY, I presume.
Setting date format (so that it matches yours; alternatively, apply TO_CHAR to the jour value with appropriate format mask):
SQL> alter session set nls_Date_format = 'yyyymmdd';
Session altered.
I shortened time span to 2 years (to save space :)).
SQL> select distinct last_day(to_date('01/01/2000','dd/mm/yyyy') + (LEVEL-1)) as jour
2 from dual
3 connect by level <= to_date('31/12/2002','dd/mm/yyyy')-to_date('01/01/2000','dd/mm/yyyy')
4 order by 1;
JOUR
--------
20000131
20000229
20000331
20000430
20000531
20000630
20000731
20000831
<snip>
20020630
20020731
20020831
20020930
20021031
20021130
20021231
36 rows selected.
SQL>
I like to use standard recursive queries rather than Oracle's specific CONNECT BY syntax. Here, you could enumerate the start of months, then offset to the end of months:
with cte (dt) as (
select date '2020-01-01' dt from dual
union all
select dt + interval '1' month from cte where dt + interval '1' month < date '2051-01-01'
)
select last_day(dt) dt from cte order by dt
Note that this uses standard date literals (date 'YYYY-MM-DD') rather than to_date() - this makes the query shorter, and, again, more standard.
Demo on DB Fiddle:
| DT |
| :-------- |
| 31-JAN-20 |
| 29-FEB-20 |
| 31-MAR-20 |
| 30-APR-20 |
| 31-MAY-20 |
...
| 31-OCT-50 |
| 30-NOV-50 |
| 31-DEC-50 |
You can do this with a CONNECT BY query. (You can also do it with a recursive query, like GMB has proposed, but it would have to be adapted to solve the problem you posed - it should allow for input start and end date, and it should return zero rows if there are no ends of month between the two dates.)
In the query below I use a WITH clause to give the start and end date. More likely, in your problem they are bind variables. (Or are they read from a table?)
Pay attention to the START WITH clause. The CONNECT BY condition is applied only to levels 2 and above; you need the START WITH condition for level=1, for the case when there are NO ends of month between the give dates (such as, between 10 January and 23 January of the same year).
with
input_dates(start_dt, end_dt) as (
select date '2020-01-22', date '2020-04-03' from dual
)
select add_months(last_day(start_dt), level - 1) as eom
from input_dates
start with last_day(start_dt) <= end_dt
connect by add_months(last_day(start_dt), level - 1) <= end_dt
;
EOM
----------
2020-01-31
2020-02-29
2020-03-31
Your initial query just needs some adjustment. Instead of just level-1 (which winds up do daily) convert it to a monthly increment "level-1) * interval '1' month. Then for the connect by just get month_between the desired date. Note: I have converted to ISO standard format for dates instead of to_date function. Makes query shorter and easier to read.
select last_day(date '2000-01-01' + (level-1)*interval '1' month) as jour
from dual
connect by level <= 1+months_between(date '2050-12-31',date '2000-01-01');
You can use a recursive sub-query.
This will work for:
Multiple input ranges;
Inputs when the start date is at the end of the month;
When the range does not contain the end of any month.
WITH input_ranges ( start_date, end_date ) AS (
-- Should return a single row.
SELECT DATE '2020-01-31', DATE '2020-02-01' FROM DUAL UNION ALL
-- Should return multiple rows.
SELECT DATE '2021-02-01', DATE '2021-06-01' FROM DUAL UNION ALL
-- Should not return any rows as there is no end of the month in the range.
SELECT DATE '2021-10-06', DATE '2021-10-20' FROM DUAL UNION ALL
-- Should work even though February does not have 30 days.
SELECT DATE '2022-01-30', DATE '2022-03-02' FROM DUAL
),
month_ends ( month_end, end_date ) AS (
SELECT LAST_DAY( start_date ),
end_date
FROM input_ranges
WHERE LAST_DAY( start_date ) <= end_date
UNION ALL
SELECT ADD_MONTHS( month_end, 1 ),
end_date
FROM month_ends
WHERE ADD_MONTHS( month_end, 1 ) <= end_date
)
SELECT month_end
FROM month_ends
ORDER BY month_end;
Which outputs:
| MONTH_END |
| :------------------ |
| 2020-01-31 00:00:00 |
| 2021-02-28 00:00:00 |
| 2021-03-31 00:00:00 |
| 2021-04-30 00:00:00 |
| 2021-05-31 00:00:00 |
| 2022-01-31 00:00:00 |
| 2022-02-28 00:00:00 |
db<>fiddle here

Count if date in date column is between start and end date [ Oracle SQL ]

This is my first post, so I hope I've posted this one correctly.
My problem:
I want to count the number of active customers per day, the last 30 days.
What I have so far:
In the first column I want to print today, and the last 29 days. This I have done with
select distinct trunc(sysdate-dayincrement, 'DD') AS DATES
from (
select level as dayincrement
from dual
connect by level <= 30
)
I've picked it up here at stackoverflow, and it works perfectly. I can even extend the number of days returned to ex. 365 days. Perfect!
I also have a table that looks like this
|Cust# | Start date | End date |
| 1000 | 01.01.2015 | 31.12.2015|
| 1001 | 02.01.2015 | 31.12.2016|
| 1002 | 02.01.2015 | 31.03.2015|
| 1003 | 03.01.2015 | 31.08.2015|
This is where I feel the problem starts
I would like to get this result:
| Dates | # of cust |
|04.01.2015| 4 |
|03.01.2015| 4 |
|02.01.2015| 3 |
|01.01.2015| 1 |
Here the query would count 1 if:
Start date <= DATES
End date >= DATES
Else count 0.
I just don't know how to structure the query.
I tried this, but it didn't work.
count(
IF ENDDATE <= DATES THEN
IF STARTDATE >= DATES THEN 1 ELSE 0 END IF
ELSE
0
END IF
) AS CUST
Any ideas?
The following produces the results you're looking for. I had change the date generator to start on 04-JAN-2015 instead of SYSDATE (which is, of course, in the year 2016), and to use LEVEL-1 to include 'current' day:
WITH CUSTS AS (SELECT 1000 AS CUST_NO, TO_DATE('01-JAN-2015', 'DD-MON-YYYY') AS START_DATE, TO_DATE('31-DEC-2015', 'DD-MON-YYYY') AS END_DATE FROM DUAL UNION ALL
SELECT 1001 AS CUST_NO, TO_DATE('02-JAN-2015', 'DD-MON-YYYY') AS START_DATE, TO_DATE('31-DEC-2016', 'DD-MON-YYYY') AS END_DATE FROM DUAL UNION ALL
SELECT 1002 AS CUST_NO, TO_DATE('02-JAN-2015', 'DD-MON-YYYY') AS START_DATE, TO_DATE('31-MAR-2015', 'DD-MON-YYYY') AS END_DATE FROM DUAL UNION ALL
SELECT 1003 AS CUST_NO, TO_DATE('03-JAN-2015', 'DD-MON-YYYY') AS START_DATE, TO_DATE('31-AUG-2015', 'DD-MON-YYYY') AS END_DATE FROM DUAL ),
DATES AS (SELECT DISTINCT TRUNC(TO_DATE('04-JAN-2015', 'DD-MON-YYYY') - DAYINCREMENT, 'DD') AS DT
FROM (SELECT LEVEL-1 AS DAYINCREMENT
FROM DUAL
CONNECT BY LEVEL <= 30))
SELECT d.DT, COUNT(*)
FROM CUSTS c
CROSS JOIN DATES d
WHERE d.DT BETWEEN c.START_DATE AND c.END_DATE
GROUP BY d.DT
ORDER BY DT DESC
Best of luck.
You could write a CASE expression equivalent to your IF-ELSE construct.
For example,
SQL> SELECT COUNT(
2 CASE
3 WHEN hiredate <= sysdate
4 THEN 1
5 ELSE 0
6 END ) AS CUST
7 FROM emp;
CUST
----------
14
SQL>
However, looking at your desired output, it seems, you just need to use COUNT and GROUP BY. The date conditions should be in the filter predicate.
For example,
SELECT dates, COUNT(*)
FROM table_name
WHERE dates BETWEEN start_date AND end_date
GROUP BY dates;

SQL Query building: howto decompose periods of time in different rows

How can I build a SQL Query to decompose some periods, for example in months.
database table:
id fromdate todate value
--------------------------------------------
100 01.01.2015 01.03.2015 10
desired query result:
id fromdate todate value
--------------------------------------------
100 01.01.2015 01.02.2015 5,25
100 01.02.2015 01.03.2015 4,75
where value is based on days between the 2 dates, for example:
value(january) = 31(january nr of days) * 10(original value) / 59(total days) = 5,25
Thank you
For calculations like this you can use date dimension - a table that contains all the dates in your domain as single rows (see this for example).
Once you have date dimension in your database things become simple:
WITH data_by_date AS
( -- Here we join dates to your periods to turn each row in
-- as many rows as there are days in the period.
-- We also turn value field into value_per_day.
SELECT
d.date,
d.month_year,
t.id,
value / (t.todate - t.fromdate) as value_per_day
FROM
dim_date d INNER JOIN
my_table t ON d.date >= t.fromdate AND d.date < t.todate
)
SELECT -- Here we group by results by month.
dd.id,
MIN(dd.date) as fromdate,
MAX(dd.date) as todate,
SUM(dd.value_per_day) as value
FROM data_by_date dd
GROUP BY dd.id, dd.month_year
Use a hierarchical query to generate a list of months for each entry:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE TEST (id, fromdate, todate, value ) AS
SELECT 100, DATE '2015-01-01', DATE '2015-03-01', 10 FROM DUAL
UNION ALL SELECT 200, DATE '2014-12-22', DATE '2015-01-06', 30 FROM DUAL
Query 1:
SELECT ID,
fromdate,
todate,
VALUE * ( todate - fromdate ) / ( maxdate - mindate ) AS value
FROM (
SELECT ID,
GREATEST( t.fromdate, m.COLUMN_VALUE ) AS fromdate,
LEAST( t.todate, ADD_MONTHS( m.COLUMN_VALUE, 1 ) ) AS todate,
t.fromdate AS mindate,
t.todate AS maxdate,
t.value
FROM TEST t,
TABLE(
CAST(
MULTISET(
SELECT ADD_MONTHS( TRUNC( t.fromdate, 'MM' ), LEVEL - 1 )
FROM DUAL
CONNECT BY
ADD_MONTHS( TRUNC( t.fromdate, 'MM' ), LEVEL - 1 ) < t.todate
)
AS SYS.ODCIDATELIST
)
) m
)
Results:
| ID | FROMDATE | TODATE | VALUE |
|-----|----------------------------|----------------------------|-------------------|
| 100 | January, 01 2015 00:00:00 | February, 01 2015 00:00:00 | 5.254237288135593 |
| 100 | February, 01 2015 00:00:00 | March, 01 2015 00:00:00 | 4.745762711864407 |
| 200 | December, 22 2014 00:00:00 | January, 01 2015 00:00:00 | 20 |
| 200 | January, 01 2015 00:00:00 | January, 06 2015 00:00:00 | 10 |
Use function add_months() and hierarchical subquery to generate periods for each id:
select id, d1, d2, round(value*(d2-d1)/nod, 2) value
from (
select id, value, todate-fromdate nod, add_months(fromdate, level-1) d1,
least(add_months(fromdate, level), todate) d2
from data
connect by add_months(fromdate, level) <= trunc(add_months(todate, 1)-1)
and id = prior id and prior dbms_random.value is not null )
SQLFiddle demo

Get the difference between two dates both In Months and days in sql

I need to get the difference between two dates say if the difference is 84 days, I should probably have output as 2 months and 14 days, the code I have just gives the totals. Here is the code
SELECT Months_between(To_date('20120325', 'YYYYMMDD'),
To_date('20120101', 'YYYYMMDD'))
num_months,
( To_date('20120325', 'YYYYMMDD') - To_date('20120101', 'YYYYMMDD') )
diff_in_days
FROM dual;
Output is:
NUM_MONTHS DIFF_IN_DAYS
2.774193548 84
I need for example the output for this query to be either 2 months and 14 days at worst, otherwise I won't mind if I can have the exact days after the months figure because those days are not really 14 because all months do not have 30 days.
select
dt1, dt2,
trunc( months_between(dt2,dt1) ) mths,
dt2 - add_months( dt1, trunc(months_between(dt2,dt1)) ) days
from
(
select date '2012-01-01' dt1, date '2012-03-25' dt2 from dual union all
select date '2012-01-01' dt1, date '2013-01-01' dt2 from dual union all
select date '2012-01-01' dt1, date '2012-01-01' dt2 from dual union all
select date '2012-02-28' dt1, date '2012-03-01' dt2 from dual union all
select date '2013-02-28' dt1, date '2013-03-01' dt2 from dual union all
select date '2013-02-28' dt1, date '2013-04-01' dt2 from dual union all
select trunc(sysdate-1) dt1, sysdate from dual
) sample_data
Results:
| DT1 | DT2 | MTHS | DAYS |
----------------------------------------------------------------------------
| January, 01 2012 00:00:00 | March, 25 2012 00:00:00 | 2 | 24 |
| January, 01 2012 00:00:00 | January, 01 2013 00:00:00 | 12 | 0 |
| January, 01 2012 00:00:00 | January, 01 2012 00:00:00 | 0 | 0 |
| February, 28 2012 00:00:00 | March, 01 2012 00:00:00 | 0 | 2 |
| February, 28 2013 00:00:00 | March, 01 2013 00:00:00 | 0 | 1 |
| February, 28 2013 00:00:00 | April, 01 2013 00:00:00 | 1 | 1 |
| August, 14 2013 00:00:00 | August, 15 2013 05:47:26 | 0 | 1.241273 |
Link to test: SQLFiddle
Updated for correctness. Originally answered by #jen.
with DATES as (
select TO_DATE('20120101', 'YYYYMMDD') as Date1,
TO_DATE('20120325', 'YYYYMMDD') as Date2
from DUAL union all
select TO_DATE('20120101', 'YYYYMMDD') as Date1,
TO_DATE('20130101', 'YYYYMMDD') as Date2
from DUAL union all
select TO_DATE('20120101', 'YYYYMMDD') as Date1,
TO_DATE('20120101', 'YYYYMMDD') as Date2
from DUAL union all
select TO_DATE('20130228', 'YYYYMMDD') as Date1,
TO_DATE('20130301', 'YYYYMMDD') as Date2
from DUAL union all
select TO_DATE('20130228', 'YYYYMMDD') as Date1,
TO_DATE('20130401', 'YYYYMMDD') as Date2
from DUAL
), MONTHS_BTW as (
select Date1, Date2,
MONTHS_BETWEEN(Date2, Date1) as NumOfMonths
from DATES
)
select TO_CHAR(Date1, 'MON DD YYYY') as Date_1,
TO_CHAR(Date2, 'MON DD YYYY') as Date_2,
NumOfMonths as Num_Of_Months,
TRUNC(NumOfMonths) as "Month(s)",
ADD_MONTHS(Date2, - TRUNC(NumOfMonths)) - Date1 as "Day(s)"
from MONTHS_BTW;
SQLFiddle Demo :
+--------------+--------------+-----------------+-----------+--------+
| DATE_1 | DATE_2 | NUM_OF_MONTHS | MONTH(S) | DAY(S) |
+--------------+--------------+-----------------+-----------+--------+
| JAN 01 2012 | MAR 25 2012 | 2.774193548387 | 2 | 24 |
| JAN 01 2012 | JAN 01 2013 | 12 | 12 | 0 |
| JAN 01 2012 | JAN 01 2012 | 0 | 0 | 0 |
| FEB 28 2013 | MAR 01 2013 | 0.129032258065 | 0 | 1 |
| FEB 28 2013 | APR 01 2013 | 1.129032258065 | 1 | 1 |
+--------------+--------------+-----------------+-----------+--------+
Notice, how for the last two dates, Oracle reports the decimal part of months (which gives days) incorrectly. 0.1290 corresponds to exactly 4 days with Oracle considering 31 days in a month (for both March and April).
I think that your question is not defined well enough, for the following reason.
Answers relying on months_between have to deal with the following issue: that the function reports exactly one month between 2013-02-28 and 2013-03-31, and between 2013-01-28 and 2013-02-28, and between 2013-01-31 and 2013-02-28 (I suspect that some answerers have not used these functions in practice, or are now going to have to review some production code!)
This is documented behaviour, in which dates that are both the last in their respective months or which fall on the same day of the month are judged to be an integer number of months apart.
So, you get the same result of "1" when comparing 2013-02-28 with 2013-01-28 or with 2013-01-31, but comparing it with 2013-01-29 or 2013-01-30 gives 0.967741935484 and 0.935483870968 respectively -- so as one date approaches the other the difference reported by this function can increase.
If this is not an acceptable situation then you'll have to write a more complex function, or just rely on a calculation that assumes 30 (for example) days per month. In the latter case, how will you deal with 2013-02-28 and 2013-03-31?
is this what you've ment ?
select trunc(months_between(To_date('20120325', 'YYYYMMDD'),to_date('20120101','YYYYMMDD'))) months,
round(To_date('20120325', 'YYYYMMDD')-add_months(to_date('20120101','YYYYMMDD'),
trunc(months_between(To_date('20120325', 'YYYYMMDD'),to_date('20120101','YYYYMMDD'))))) days
from dual;
Here I'm just doing the difference between today, and a CREATED_DATE DATE field in a table, which obviously is a date in the past:
SELECT
((FLOOR(ABS(MONTHS_BETWEEN(CREATED_DATE, SYSDATE))) / 12) * 12) || ' months, ' AS MONTHS,
-- we take total days - years(as days) - months(as days) to get remaining days
FLOOR((SYSDATE - CREATED_DATE) - -- total days
(FLOOR((SYSDATE - CREATED_DATE)/365)*12)*(365/12) - -- years, as days
-- this is total months - years (as months), to get number of months,
-- then multiplied by 30.416667 to get months as days (and remove it from total days)
FLOOR(((SYSDATE - CREATED_DATE)/365)*12 - (FLOOR((SYSDATE - CREATED_DATE)/365)*12)) * (365/12))
|| ' days ' AS DAYS
FROM MyTable
I use (365/12), or 30.416667, as my conversion factor because I'm using total days and removing years and months (as days) to get the remainder number of days. It was good enough for my purposes, anyway.
The solution I post will consider a month with 30 days
select CONCAT (CONCAT (num_months,' MONTHS '), CONCAT ((days-(num_months)*30),' DAYS '))
from (
SELECT floor(Months_between(To_date('20120325', 'YYYYMMDD'),
To_date('20120101', 'YYYYMMDD')))
num_months,
( To_date('20120325', 'YYYYMMDD') - To_date('20120101', 'YYYYMMDD') )
days
FROM dual);
Find out Year - Month- Day between two Days in Orale Sql
select
trunc(trunc(months_between(To_date('20120101', 'YYYYMMDD'),to_date('19910228','YYYYMMDD')))/12) years ,
trunc(months_between(To_date('20120101', 'YYYYMMDD'),to_date('19910228','YYYYMMDD')))
-
(trunc(trunc(months_between(To_date('20120101', 'YYYYMMDD'),to_date('19910228','YYYYMMDD')))/12))*12
months,
round(To_date('20120101', 'YYYYMMDD')-add_months(to_date('19910228','YYYYMMDD'),
trunc(months_between(To_date('20120101', 'YYYYMMDD'),to_date('19910228','YYYYMMDD'))))) days
from dual;
SELECT (MONTHS_BETWEEN(date2,date1) + (datediff(day,date2,date1))/30) as num_months,
datediff(day,date2,date1) as diff_in_days FROM dual;
// You should replace date2 with TO_DATE('2012/03/25', 'YYYY/MM/DD')
// You should replace date1 with TO_DATE('2012/01/01', 'YYYY/MM/DD')
// To get you results
See the query below (assumed #dt1 >= #dt2);
Declare #dt1 datetime = '2013-7-3'
Declare #dt2 datetime = '2013-5-2'
select abs(DATEDIFF(DD, #dt2, #dt1)) Days,
case when #dt1 >= #dt2
then case when DAY(#dt2)<=DAY(#dt1)
then Convert(varchar, DATEDIFF(MONTH, #dt2, #dt1)) + CONVERT(varchar, ' Month(s) ') + Convert(varchar, DAY(#dt1)-DAY(#dt2)) + CONVERT(varchar, 'Day(s).')
else Convert(varchar, DATEDIFF(MONTH, #dt2, #dt1)-1) + CONVERT(varchar, ' Month(s) ') + convert(varchar, abs(DATEDIFF(DD, #dt1, DateAdd(Month, -1, #dt1))) - (DAY(#dt2)-DAY(#dt1))) + CONVERT(varchar, 'Day(s).')
end
else 'See asumption: #dt1 must be >= #dt2'
end In_Months_Days
Returns:
Days | In_Months_Days
62 | 2 Month(s) 1Day(s).