Weeks in month adjustment in oracle sql - sql

I have salesdate for whole last year (01/01/2012 to 12/31/2012). I want to create
a week variable in such a way that there are only 4 weeks consistent over the months.
In other words, I want
01/01/2012-01/07/2012 = week1
01/08/2012-01/14/2012 = week2
01/15/2012-01/21/2012 = week3
01/22/2012-01/31/2012 = week4
(I can not use ww. format because my week 4 does not fit the always definition of week 4 in Oracle SQL Developer.)
I am wondering if anybody can help me on this.

Try this expression:
select LEAST(TRUNC((EXTRACT(day FROM salesdate) + 6) / 7), 4) week
FROM salesdata;
Note:
EXTRACT extracts the day from the date
TRUNC( (x + 6) / 7) divides it by seven days and truncates it to an integer number
LEAST( x, 4 ) limits it to a maximum of 4

Well your last week has 9 days, so that is kind of weird...
but you could try something like:
CREATE OR REPLACE FUNCTION GET_WEIRD_WEEK(I_DATE DATE)
RETURN NUMBER AS
BEGIN
RETURN CASE
WHEN FLOOR(TO_CHAR(I_DATE,'DD')/7)+1 > 3
THEN 4
ELSE FLOOR(TO_CHAR(I_DATE,'DD')/7)+1
END;
END;
otherwise i would suggest you distribute the days evenly across the month's quarters:
CREATE OR REPLACE FUNCTION GET_WEIRD_WEEK(I_DATE DATE) RETURN NUMBER AS
BEGIN
RETURN FLOOR(TO_CHAR(I_DATE,'DD')/TO_CHAR(LAST_DAY(I_DATE),'DD')*4)+1;
END;

Related

SQL Help - Summarize Customer Fiscal Year By Quarters

I've been at this question for a bit and I'm currently stuck:
This is my current attempt:
I only took an image of a small portion of the code since the general idea can be understood within the few case statements. It's turning out to be way too messy and I think theirs an easier way to go about it. An answer isn't necessarily needed but some guidance would help since I'd like to try it out for myself. Thank you!
are you still struggling with this one?
Create function fiscalYearSummary (#OrderDate Date, #StartFiscalYearFromGivenMonth int)
returns nvarchar(20)as
begin
declare #MonthOfYear int
declare #Quarter int
set #MonthOfYear = datepart(MONTH, #OrderDate)
set #Quarter = (((((#MonthOfYear - (#StartFiscalYearFromGivenMonth )) + 12) % 12) + 1) / 4) + 1
return case #Quarter when 1 then 'Quarter I' when 2 then 'Quarter II' when 3 then 'Quarter III' when 4 then 'Quarter IV' else 'Error' end
end
This would be used in a select
select dbo.fiscalYearSummary('20190101',1) -- January with the first month of the fiscal year January.
select dbo.fiscalYearSummary('20190401',4) -- April with the first month of the fiscal year April.
select dbo.fiscalYearSummary('20191231',1) -- December with the first month of the fiscal year January
I'm sure it can be done better, but this should get you started.
I get the Month from the passed in date (1 to 12)
Subtract #StartFiscalYearFromGivenMonth to drag it back by that many months.
Add 12 (a year) to make it positive, mod it with 12 to get it in the range 0 to 11, then add 1 to make that 1 to 12.
I divide the result by 4 to get the quarter - 0 to 3, then add 1 again, into range 1 to 4.
then a simple case returns the quarter.
I hope this helps

SSRS. Workday Function

I'm trying to convert the below Excel formula into SSRS but having looked around I cannot seem to find a solution. I can calculate the number of working days between two dates but what I'm trying to do is add on a number of working days to a date. Essentially I don't have the 2nd date.
I guess it would be something along the lines of the DATEADD function?
=WORKDAY($A1,B$1)
Hope someone can help
Many thanks
Here is a tsql solution to add X Business Days to a date.
declare #calendar as table (theDate date, dayOfWeek varchar (10));
declare #startDate as date = '20170704';
declare #businessDaysToAdd as integer = 10;
insert into #calendar
select theDate
, datename(dw, theDate) dow
from
dbo.dateTable('20170701', '20170720') ;
with temp as (
select theDate
, dayOfWeek
, rank() over (order by theDate) theRank
from #calendar
where theDate > #startDate
and dayOfWeek not in ('Saturday', 'Sunday')
)
select * from temp
where theRank = #businessDaysToAdd;
Notes
dbo.DateTable is a table valued function that just happens to exist in the database I was using. In real life, you might have an actual calendar table of some sort.
This example does not include holidays.
This is only the start of the answer to the posted question. It only solves the problem of Essentially I don't have the 2nd date.
Type this into the expression for the textbox. (From SSRS 2008 Datediff for Working Days)
=(DateDiff(DateInterval.day,Parameters!STARTDATE.Value,Parameters!ENDDATE.Value)+1)
-(DateDiff(DateInterval.WeekOfYear,Parameters!STARTDATE.Value,Parameters!ENDDATE.Value)*2)
-(iif(Weekday(Parameters!STARTDATE.Value) = 7,1,0)
-(iif(Weekday(Parameters!ENDDATE.Value) = 6,1,0))-1)
Ok after much perseverance I managed to get what I wanted in both TSQL and SSRS. My objective was to measure Agent productivity so I didn’t want to count the weekend and this would be unfair. If a date fell on a weekend then I wanted it to jump to a Monday. Likewise if adding number of days onto a date went over a weekend in the future then I needed the incremented date to reflect this. For the end user (In SSRS) I wanted a leading edge (Like an Upside down triangle) so that if the date + number working days was in the future then set to NULL, showing a zero would look like no productivity which is incorrect.
First TSQL - My base query started with the following SO thread but after trying many of the options I was finding when the date fell on a Saturday or Sunday the solution did not work for me (I was unable to create functions due to permissions). However tweaking the below got me there and I dealt with Sunday specifically
Add business days to date in SQL without loops
SELECT
,DATEADD(WEEKDAY, (/*Your Working Days*//5)*7+(/*Your Working Days*/ % 5) +
(CASE WHEN DATEPART(WEEKDAY,/*Your Date*/) <>7 AND DATEPART(WEEKDAY,/*Your Date*/) + (/*Your Working Days*/ % 5) >5 THEN 2
WHEN DATEPART(WEEKDAY,/*Your Date*/) = 7 AND DATEPART(WEEKDAY,/*Your Date*/) + (/*Your Working Days*/ % 5) >5 THEN 1 ELSE 0 END), /*Your Date*/) AS [IncrementedDate]
FROM /*YourTable*/
Then for SSRS - The 2 key points here is that TSQL will divide as an integer if the source number is an integer so this needs to be handled in SSRS and secondly you need to set the first week day to Monday as part of the expression.
I put this expression into a Matrix with Date Created being my Row Group and Contact Working Days being my Column Group.
=DATEADD("W",(INT(ReportItems!ContactWorkingDays.Value/5))*7+(ReportItems!ContactWorkingDays.Value MOD 5) + IIF(DATEPART("W",ReportItems!DateCreated.Value,FirstDayOfWeek.Monday) <> 7 AND (DATEPART("W",ReportItems!DateCreated.Value,FirstDayOfWeek.Monday) + (ReportItems!ContactWorkingDays.Value MOD 5) >5),2,IIF(DATEPART("W",ReportItems!DateCreated.Value,FirstDayOfWeek.Monday) = 7 AND (DATEPART("W",ReportItems!DateCreated.Value,FirstDayOfWeek.Monday) + (ReportItems!ContactWorkingDays.Value MOD 5) >5),1,0)),ReportItems!DateCreated.Value)
This does not include holidays - I'm not too bothered at this stage and that is for a rainy day! :)

How to convert and display an Integer into YYYYMMDD format using Select query without neglecting days and leap year logic?

I have a query to retrieve a set of non null records from a column x consisting of DATE format.
If count(x) = 35 then i need to display the value as 1 Month & 5 days
If 369 days then 1 year & 4 days or If 400 days then 1 year 1 month 5 days respectively
Query: In the above instance,unfortunately i am neglecting 0.25 days but How to tweak my actual requirement in such a way that i don't end up neglecting days and handle leap year logic too
How to solve this issue?
it is not clear if you need of a time's generic computing in years, months and days, based on averages of number of days of a month, etc.. or if you want an exact compute of the number of the months that pass starting froma adate.. for example if your total sum of 400 days start from 15 march, then the month is counted by 1 after, let's say, 15 days, and so the remaining days are 20.. I don't know if I explained..
In the first hypotesis, you may use the following pseudo-coded solution, that is a very approximative method..
however, if you know a start date, it is possible to compute exactly how many "bissextile" days are comprehended between your interval of days starting from your start date
let's say to have output variables Years, Months, Days .. and an input totalDaysdays assigned with your data retrieved from the db, then:
(pseudocode)
Years = trunc((totalDays / 365)
bissextileDays = trunc((totalDays / 365) / 4)
numDaysOffset = (totalDays Mod 365) + bissextileDays
Months = trunc(numDaysOffset / 30)
Days = numDaysOffset Mod 30
Actually i found something that will suit my requirement.
https://community.oracle.com/thread/2587161?start=0&tstart=0
select days,
floor(days / 365.25) years,
floor(mod(days,365.25) / (365.25 / 12)) months,
round(mod(days,365.25 / 12)) days
from periods
So this can produce expected output when number is given. This produces output as years,months and remaining days

How to get every Monday out of a Date

I need some help to understand a certain line in a code. The code takes the turnovers of every Monday in the year 2010 and at the last line in summarizes all the turnovers to one.
Here is the code:
SELECT
CASE
WHEN GROUPING (DATUM) = 1 THEN 'Gesamtumsatz'
ELSE CAST (DATUM AS VARCHAR (40))
END AS MONTAGSDATEN,
AVG (VERKAUFSWERT * VERKAUFSMENGE) as UMSATZ
FROM Data_Star_Awesome.dbo.VERKAUFSFAKTEN vk
INNER JOIN DIMDATUM dimD on vk.DATUMID=dimD.DATUMID
WHERE DATEDIFF(dd,0, DATUM)%7=0
AND JAHR = 2010
GROUP BY ROLLUP (DATUM)
The problematic line I don't understand is the following:
WHERE DATEDIFF(dd,0, DATUM)%7=0
What I know is that it takes the days out of the date variable but I don't get the %7=0 part. The DATEDIFF function should give back all the days. Are these days saved in the % the placeholder? And how does it get all the Mondays by using the 7=0?
It would be great if someone could help me out.
Thanks a lot :)
Modulo or % operator is the same as in a lot of programming languages. It returns the remainder after the division.
The DATEDIFF function takes two dates and returns the difference in a specified datepart, which in your query is the days represented by dd.
Also 0 as date converts to 1/1/1900 which happens to be a Monday. So your query is calculating the days between 1/1/1900 and the DATUM field in days and if its Mod is 0 then DATUM is Monday.
You could simply say:
datename(weekday,<datetime-value>)
Which will return 'Monday', 'Tuesday', 'Wednesday', etc. The problem with this approach is that the returned value is localized. If the SQL server's language is changed, your test for 'Monday' will fail.
This expression will always work:
( ##datefirst + ( datepart(weekday,today) - 1 ) ) % 7
It evaluates to 1-7, where Monday is always 1 and Sunday is always 7, regardless of culture/language settings or the current value of ##datefirst, as set by set datefirst.
We can then convert this into this discriminant function, yielding 1 or 0 to indicate whether or not the date is Monday:
case ( ##datefirst + ( datepart(weekday,today) - 1 ) ) % 7 when 1 then 1 else 0 end

Need to create Financial Year entries in Oracle 11g DB

I need a financial year entries based on current or today's date AND time in Oracle11g DB.
Suppose if we consider today's date is 1ST April 2013, then i need the outputs as 01-APR-13 and 31-MAR-14.
Our requirement financial Year considered is from April (the current year) to March (following year).
Based on current datetime...the scenario of output depends on the current date-time which falls in the above said period or duration.
Another example: If we take today's datetime as 28th Dec 2012, then the output is needed as 01-APR-12 and 31-MAR-13.
Please help how to acheive the same in very short format using only SQL.
Consider the below table as
Create table venky (financialYearFrom DATE NOTNULL, financialYearTo DATE NOTNULL);
Something ugly:
SELECT to_date('1-APR-'||(to_char(sysdate,'yyyy')+
(case when to_char(sysdate,'mm')>3
then 0
else -1
end))) AS start_date ,
to_date('31-MAR-'||(to_char(sysdate,'yyyy')+
(case when to_char(sysdate,'mm')>3
then 1
else 0
end))) end_date
FROM dual;
If month > 3 then add a year to 31-MAR(end_of_period), else substract a year to 1-APR (start_of_period).
UPDATE: Something nicer:
select add_months(trunc(add_months(sysdate,-3),'yyyy'),3) as start_date ,
add_months(trunc(add_months(sysdate,-3),'yyyy'),15)-1 as end_date
from dual
Substracting 3 months will send you to the correct start year. Truncating to year and adding 3 months sends you to 1 APR. End_of period is 12 months ahead start minus one day.
create user define function for that here is example for SQL SERVER
find how to do it in oracle (both are same with minor diff in syntax)
CREATE FUNCTION [dbo].[getYear]
(
-- Add the parameters for the function here
#CurDate DATETIME
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #Y int;
SELECT #Y = CASE WHEN MONTH(#CurDate) <= 3 THEN YEAR(#CurDate) - 1 ELSE YEAR(#CurDate) END;
RETURN '01-APR-' + LTRIM(STR(#Y)) + ' and 31-MAR-' + LTRIM(STR(#Y+1));
END
and use it like this
Select dbo.GETYEAR(GETDATE());