Oracle correctly getting the month difference - sql

Hi Ive been having an issue with getting the correct difference in a date from the current month not including the day.
ie if the month when the query is run is march 2013
then the following should be the result
EXECUTION_DATE, EXEC_DIFF
01-FEB-13, 1
31-JAN-13, 2
30-JAN-13, 2
however using the below sql statement im getting
EXECUTION_DATE, EXEC_DIFF
01-FEB-13, 1
31-JAN-13, 2
30-JAN-13, 1
select EXECUTION_DATE,
floor(MONTHS_BETWEEN (trunc(sysdate,'MM')-1, EXECUTION_DATE))+1 "EXEC_DIFF"
from V_CERT_LIST
WHERE EXECUTION_DATE < TO_DATE('02/02/2013','DD/MM/YYYY')
ORDER BY EXECUTION_DATE DESC
Please can someone put me right ive been bashing my head with this for some time now
thanks

select EXECUTION_DATE,
MONTHS_BETWEEN (trunc(sysdate,'MM'), trunc(EXECUTION_DATE,'MM')) "EXEC_DIFF"
from V_CERT_LIST
WHERE EXECUTION_DATE < TO_DATE('02/02/2013','DD/MM/YYYY')
ORDER BY EXECUTION_DATE DESC

Not looking for scores but cannot understand what is the problem with months_between? In my understanding it does not matter when in month execution takes place - Jan-31 or Jan 30... The difference is still 2 months between Jan and Mar as in your example. I can add more days in month in the query but mo_betw. will still be the same...:
SELECT to_char(exec_date, 'DD-MON-YYYY') exec_date, MONTHS_BETWEEN(run_date, exec_date) months_btwn
FROM
(
SELECT to_date('01/03/2013', 'DD/MM/YYYY') run_date
, Add_Months(Trunc(sysdate,'YEAR'),Level-1) exec_date -- first day of each month
FROM dual
CONNECT BY LEVEL <= 3
)
/
EXEC_DATE MONTHS_BTWN
------------------------
01-JAN-2013 2
01-FEB-2013 1
01-MAR-2013 0

Months_Between has complex logic that takes the day of the month into account.
Perhaps what you want is this:
select EXECUTION_DATE,
((year(sysdate)*12+month(sysdate)) - (year(execution_date)*12 + month(execution_date))
) as Exec_Diff
from V_CERT_LIST
WHERE EXECUTION_DATE < TO_DATE('02/02/2013','DD/MM/YYYY')
ORDER BY EXECUTION_DATE DESC
This converts the year/month combination into the number of months since 0 time and then subtracts the results.

Related

Get All records of previous date from current date in oracle

I want all the data from a table which is more than 6 months available in my table. So for that I wrote the below query but it wasn't giving the exact records.
Select * from changerequests where lastmodifiedon < sysdate - 180;
The issue is I was getting the records for 2nd april, 2020 which is not more than 6 months. Please suggest the query
If you want records that were last modified within the last 6 months, then you want the inequality condition the other way around:
where lastmodifiedon > sysdate - 180
Note that 180 days is not exactly 6 months. You might want to use add_months() for something more accurate:
where lastmodifiedon > add_months(sysdate, -12)

Data of last 6 quarter including current quarter

How to get data of last 6 quarter in Oracle including current quarter. I mean if I run the query today so data between 01-JAN-2018 to 30-JUN-2019 should come in the query.
You could do something like this:
SELECT
*
FROM
DUAL
WHERE
DATE_FIELD >= (SYSDATE - (30*(3*6)))
What this query is doing is taking the current date (SYSDATE), and grabbing all values from the previous 6 quarters. The rationale is:
30 = days in a month | 3 = months in a quarter | 6 = quarters specified by OP
You can use add_months and trunc functions for date value with Q(quarter) argument
select t.*
from tab t
where insert_date between
trunc(add_months(sysdate,-3*5),'Q')
and trunc(add_months(sysdate,3),'Q')-1;
Demo for verification
for the starting date, -3*(6-1) = -3*5 considered, starting from 5 quarter back to be able to count 6 quarter including the current quarter. 3 is
obvious as being the number of months in each quarter.

Average ticket response time by week with SQL query

In my Spiceworks database there is a table, tickets, with two columns I am concerned with, first_response_secs and created_at.
I have been tasked with finding the average response time of tickets for every week.
So if I run the following query:
select AVG(first_response_secs) from (
select first_response_secs,created_at
from tickets
where created_at BETWEEN '2017-03-19' and '2017-03-25'
)
I will get back the average first response seconds for that week. But that's as far as my limited SQL gets me. I need 6 months worth of data and I don't want to manually edit the date range and rerun the query 24 times.
I would like to write a query that will return output similar to the following:
WEEK AVERAGE RESPONSE TIME(secs)
-----------------------------------------------------------
2017-02-26 - 2017-03-04 21447
2017-03-05 - 2017-03-11 20564
2017-03-12 - 2017-03-18 25883
2017-03-19 - 2017-03-25 12244
Or something like that, back 6 months.
Weeks are tricky. How about:
select min(created_at) as weekstart, first_response_secs, created_at
from tickets
group by floor(julianday('2017-03-25) - julianday(created_at)) % 7 = 0
order by weekstart
One dirty way is to use case to define week boundaries:
select week, avg(first_response_secs)
from (
select case
when created_at between '2017-02-26' and '2017-03-04' then '2017-02-26 - 2017-03-04'
when created_at between '2017-03-05' and '2017-03-11' then '2017-03-05 - 2017-03-11'
when created_at between '2017-03-12' and '2017-03-18' then '2017-03-12 - 2017-03-18'
when created_at between '2017-03-19' and '2017-03-25' then '2017-03-19 - 2017-03-25'
end as week,
first_response_secs
from tickets
) t
group by week;
Demo
Note that this method is a general purpose one and can be modified to change the boundaries as you wish.

Why I lost the days from 2-6? It shows always days in a 7 days turn

TRUNC (ADD_MONTHS(DATE, - CASE WHEN COUNTRYCODE='TH'
AND DATE >= (CURRENT_DATE+1)
THEN 6516 ELSE 0 END)
, 'day' ) as RDATE,
When you use TRUNC(DATE,'DAY') then it expected to display the date based on first day of week. Please refer link here where you can see below. That is the reason, you loose 2 to 6 days.
TRUNC(TO_DATE('22-AUG-03'), 'DAY')
Result: '17-AUG-03'

How can I get a table of dates from the first day of the month, two months ago, to yesterday?

I have a situation that I would normally solve by creating a feeder table (for example, every date between five years ago and a hundred years into the future) for querying but, unfortunately, this particular job disallows creation of such a table.
So I'm opening this up to the SO community. Today is Jan 29, 2010. What query could I run that would give a table with a single date column with values ranging from Nov 1, 2009 through Jan 28, 2010 inclusive? On Feb 1, it should give me every date from Dec 1, 2009 through Jan 31, 2010.
I'm using DB2 but I'm happy to see any other solutions on the off-chance they may provide a clue.
I know I can select CURRENT DATE from sysibm.sysdummy1 (or dual for Oracle bods) but I'm not sure how to immediately select a date range without a physical backing table.
This just does sequential days between two dates, but I've posted to show you can eliminate the recursive error by supplying a limit.
with temp (level, seqdate) as
(select 1, date('2008-01-01')
from sysibm.sysdummy1
union all
select level, seqdate + level days
from temp
where level < 1000
and seqdate + 1 days < Date('2008-02-01')
)
select seqdate as CalendarDay
from temp
order by seqdate
Update from pax:
This answer actually put me on the right track. You can get rid of the warning by introducing a variable that's limited by a constant. The query above didn't have it quite right (and got the dates wrong, which I'll forgive) but, since it pointed me to the problem solution, it wins the prize.
The code below was the final working version (sans warning):
WITH DATERANGE(LEVEL,DT) AS (
SELECT 1, CURRENT DATE + (1 - DAY(CURRENT DATE)) DAYS - 2 MONTHS
FROM SYSIBM.SYSDUMMY1
UNION ALL SELECT LEVEL + 1, DT + 1 DAY
FROM DATERANGE
WHERE LEVEL < 1000 AND DT < CURRENT DATE - 1 DAY
) SELECT DT FROM DATERANGE;
which outputs, when run on the 2nd of February:
----------
DT
----------
2009-12-01
2009-12-02
2009-12-03
: : : :
2010-01-30
2010-01-31
2010-02-01
DSNE610I NUMBER OF ROWS DISPLAYED IS 63
DSNE616I STATEMENT EXECUTION WAS SUCCESSFUL.
just an idea (not even sure how you'd do this), but let's say you knew how many days you wanted. Like 45 days. If you could get a select to list 1-45 you could do date arithmetic to subtract that number from your reference data (ie today).
This kind of works (in MySQL):
set #i = 0;
SELECT #i:=#i+1 as myrow, ADDDATE(CURDATE(), -#i)
FROM some_table
LIMIT 10;
The trick i have is how to get the 10 to be dynamic. If you can do that then you can use a query like this to get the right number to limit.
SELECT DATEDIFF(DATE_SUB(CURDATE(), INTERVAL 1 DAY),
DATE_SUB(LAST_DAY(CURDATE()), INTERVAL 2 MONTH))
FROM dual;
I haven't used DB2 before but in SQL Server you could do something like the following. Note that you need a table with at least the number of rows as you need days.
SELECT TOP 45
DATEADD(d, ROW_NUMBER() OVER(ORDER BY [Field]) * -1, GETDATE())
FROM
[Table]