Using a UDF function in a query - sql

I have the following Code which points at the DateDimension which works out the actual mins of business opening hours and closing ours. I am hoping to use the output of the query to pass on to my main query to identify the sum total of minutes business is open. This will allow me to exclude bank holidays and sundays if necessary. However I am having problems creating the function. Cannot find either column "dbo" or the user-defined function or aggregate "dbo.GetWorkingDaysMin", or the name is ambiguous.
this end query I expect to look like this
SELECT dbo.GetWorkingDaysMin([WebLeadRecd_DKey],[ContactSucces_DKey]), COLUMN1, column2 etc AS Name
FROM [dbo].[TEST_DATES]
this is the function below
alter FUNCTION GetWorkingDaysMin
(
#Date1 INT,
#Date2 INT
)
RETURNS table AS
RETURN
(
SELECT SUM(TotalMinsOpen) AS TotalMinOpen, SUM(TotalMinsClosed) AS TotalMinClosed,
FROM [dbo].[DIM_DATE]
WHERE DateKey BETWEEN #Date1 AND #Date2
)
I am just wondering if this is the best way to exclude bank holidays and sundays, the opening hours of the business are 8am - 6pm Mon -Fri and Satu 8am - 1pm. Also perhaps you can advise on the next stage as well, I am thinking about using cases statements to do a bit of airthmetics but am I setting myseld up for a failure taking that approach or is there a better way?

You have defined a table valued function because you are returning two values. Then you are using it as a scalar function. Instead, call it as:
SELECT wdm.*, td.*
FROM dbo.TEST_DATES td CROSS APPLY
dbo.GetWorkingDaysMin(td.WebLeadRecd_DKey, td.ContactSucces_DKey) wdm;

Related

Need a efficient query way to calculate sum of work days in snowflake(without using function)

I have a Date Dimension which has the date column( having dates from 2010 to 2020) along with the Isworkday bit column (which is either 0 or 1). All the holidays are calculated and pre-populated in the dimension.
Now, I have a table which gives the start_date and end_datecolumns and I need to calculate the sum_of_workdays in those two date ranges using the date dimension.
(I know I can create a function which accepts start date and end date and returns sum of work days using date dimension but snowflake is really inefficient with functions hence i want to do with sub queries or joins or anything)
This is the function i currently use:
create or replace function Sum_Of_WorkDays(start_date TIMESTAMP, end_date TIMESTAMP)
returns int
as--to get sume of workdays in a given date range
$$
SELECT sum(ISWORKDAY)
FROM DATE_DIMENSION
WHERE "DATE" BETWEEN start_date AND end_date
$$
;
And below is how am calling the function from the table to calculate sum but takes lot of time if there are joins and cte involved in the query::
select Sum_Of_WorkDays(start_date,end_date) from table
Any efficient query for it other than using a function?
Conclusion: Ended up using Left join for each sum calculations to optimize it. Snowflake apparently sometimes is not that good in query optimization.

What is the fastest way to populate table with dates after certain day?

Let's assume that we have the following input parameters:
date [Date]
period [Integer]
The task is the following: build the table which has two columns: date and dayname.
So, if we have date = 2018-07-12 and period = 3 the table should look like this:
date |dayname
-------------------
2018-07-12|THURSDAY
2018-07-13|FRIDAY
2018-07-14|SATURDAY
My solution is the following:
select add_days(date, -1) into previousDay from "DUMMY";
for i in 1..:period do
select add_days(previousDay, i) into nextDay from "DUMMY";
:result.insert((nextDay, dayname(nextDay));
end for;
but I don't like the loop. I assume that it might be a problem in the performance if there are more complicated values that I want to put to result table.
What would be the better solution to achieve the target?
Running through a loop and inserting values one by one is most certainly the slowest possible option to accomplish the task.
Instead, you could use SAP HANA's time series feature.
With a statement like
SELECT to_date(GENERATED_PERIOD_START)
FROM SERIES_GENERATE_TIMESTAMP('INTERVAL 1 DAY', '01.01.0001', '31.12.9999')
you could generate a bounded range of valid dates with a given interval length.
In my tests using this approach brought the time to insert a set of dates from ca. 9 minutes down to 7 seconds...
I've written about that some time ago here and here if you want some more examples for that.
In those examples, I even included the use of series tables that allow for efficient compression of timestamp column values.
Series Data functions include SERIES_GENERATE_DATE which returns a set of values in date data format. So you don't have to bother to convert returned data into desired date format.
Here is a sample code
declare d int := 5;
declare dstart date := '01.01.2018';
SELECT generated_period_start FROM SERIES_GENERATE_DATE('INTERVAL 1 DAY', :dstart, add_days(:dstart, :d));

MS Access - Problems using variables in WHERE clause

I have a working query which takes too long to run. It is being used to populate an Access form field with a list of distinct contracts ordered by their start date.
The following query returns a list of distinct contract start dates for multiple commodities (which share contract start dates) where the contract start date (DELSTART) is greater or equal to the current date (PRICEDATE).
The function returndelivery returns a date attribute of the contract converted to a double, the function returnnumericdate just returns a double from a date (yyyymmdd).
SELECT DISTINCT (tblFuturesPrices.Period),
returnnumericdate(returndelivery([PERIOD],"S")) AS DELSTART,
ReturnNumericDate(Date()) AS PRICEDATE
FROM tblFuturesPrices
WHERE returnnumericdate(returndelivery([PERIOD],"S")) >= ReturnNumericDate(Date())
GROUP BY PERIOD
ORDER BY returnnumericdate(returndelivery([PERIOD],"S"));
Ideally I would like to refer to the variables DELSTART and PRICEDATE in the where clause but Access prompts for a variable value when I do so. I think the query takes longer than it should because I'm having to use my user defined functions numerous times.
The source table (tblFutures) contains prices for each commodity / contract for working days going back 6 months.
Thanks in advance.
I think the query takes longer than it should because I'm having to
use my user defined functions numerous times.
That's it. But you can reduce those functions:
returnnumericdate(returndelivery([PERIOD],"S")) >= ReturnNumericDate(Date())
will be no different from
returndelivery([PERIOD],"S") >= Date()
Don't know what returndelivery does.
Addendum:
Filter on the raw data and create a new function returndeliverydate that does the same as returndelivery except returns a Date value:
SELECT
tblFuturesPrices.Period,
returndeliverydate([PERIOD],"S") AS DELSTART,
Date() AS PRICEDATE
FROM
tblFuturesPrices
WHERE
returndeliverydate([PERIOD],"S") >= Date()
Save this query and use it as source in a new query:
Select Distinct
DELSTART,
PRICEDATE
FROM
YourQuery

SQL CHARINDEX, SUBSTIRNG, PARSENAME better for Performance

I have a table [Evetns]- rows of
EventName, EventDateTime
Sample, 25/12/2000
I have another table with period sets as DateRange type
period_range
1/1/1999,1/1/2001
1/1/1999,24/12,2000
So the result would be
Sample, 1
The event sample with event date 25/12/2000 is found in one range of the period data.
For this I have created a function GetRange() as below
select
#var=count(*)
--, convert(datetime,PARSENAME(REPLACE(period_range,',','.'),2),103),
--convert(datetime,PARSENAME(REPLACE(period_range,',','.'),1),103)
from
[dbo].[DateRange]
where
#date between convert(datetime,PARSENAME(REPLACE(period_range,',','.'),2),103)
and convert(datetime,PARSENAME(REPLACE(period_range,',','.'),1),103)
the function receive the date from the Events table and pass it to above function which returns and int value and I am consuming the function as below,
select eventname,dbo.[getrange](eventdate) exist from [dbo].[Evetns]
The result set satisfies the requirement but need some suggestion for better performance. which should be use out of this?
Which function will be good for performance CHARINDEX, SUBSTIRNG or PARSENAME?
Is that good idea for bulk records?
any suggestions will be highly appreciated.

Access 2007 query date calculation

I have the following Access query (see above) to give me the date, X number of weeks out from the actual WorkDte that exists in the table. But, the date these expressions calculate out may not actually exists in the “CIB_Results” table due to a bank holiday etc. Is there a way to generate the same sort of data but say if it’s running the “Wk1” calculation and it calculates out 1/1/2016 (which does not exists due to the new year holiday), instead of doing [WorkDte]-7 it will move on to [WorkDte]-14 and so on, until it finds an actual date that exists in the “CIB_Results” table? I’m wanting to apply the same logic to all the fields in the query…that way they will all self adjust based off of the actual dates that exist in the “CIB_Results” table. Any help with this would be greatly appreciated!
Have a function IsHoliday(SomeDate) that looks up SomeDate in your holiday table and returns True if found.
Then create a loop:
Public Function PreviousWorkWeekday(ByVal SomeDate As Date) As Date
Do
SomeDate = DateAdd("ww", -1, SomeDate)
Loop Until Not IsHoliday(SomeDate)
PreviousWorkWeekday = SomeDate
End Function
Now use function PreviousWorkWeekday in your query.