T-SQL Scalar-valued function Return Null value - sql

I'm trying to create a Scalar-valued user defined function to substitute my original codes. Basically, I intend to calculate the percentage of 2022 "nnooftickets" data out of the 2020 data for each period, there are 13 period in a year. Unfortunately, my user defined function codes do not work and I'm struggling spotting the issue.
The following are the original codes that works fine:
SELECT
setperiod,
SUM(nnooftickets) AS sumnnoofticketsp,
CASE
WHEN setperiod like '2023%' THEN SUM(nnooftickets) *1.00 / LAG(SUM(nnooftickets),13*(2023-2020)) OVER(ORDER BY setperiod) ELSE null
END AS nnoofticketspyoy
FROM rdg.Sales
GROUP BY setperiod
Then I created a scalar function try to replace the case statement, the codes for the scalar function is as follows:
CREATE FUNCTION [rdg].[getyoy]
(
#var BIGINT, #currentyear SMALLINT, #compareyear SMALLINT, #orderbyperiod VARCHAR, #multiplygap SMALLINT
)
RETURNS DECIMAL(18,4)
AS
BEGIN
DECLARE #YOY AS DECIMAL(18,4)
SELECT #YOY = CASE WHEN #orderbyperiod like '2023%' THEN #Var*1.00 / LAG(#Var, #multiplygap*(#currentyear - #compareyear)) OVER (ORDER BY #orderbyperiod) ELSE null END
RETURN #YOY
END
GO
Finally, I call the function using the codes below:
SELECT
setperiod,
SUM(nnooftickets) AS sumnnoofticketsp,
rdg.getyoy(SUM(nnooftickets), 2023, 2020, setperiod, 13) AS ngrosspyoy
FROM rdg.Sales
GROUP BY setperiod
However, after using the scalar function, there's no output figure (i.e. receive all NULL values) for column ngrosspyoy.
Could anyone help please?

Related

Declare variables in scheduled query BigQuery;

I am developing a scheduled query where I am using the WITH statement to join and filtrate several tables from BigQuery. To filtrate the dates, I would like to declare the following variables:
DECLARE initial, final DATE;
SET initial = DATE_TRUNC(DATE_TRUNC(CURRENT_DATE(), MONTH)+7,ISOWEEK);
SET final = LAST_DAY(DATE_TRUNC(CURRENT_DATE(), MONTH)+7, ISOWEEK);
However, when executing this query, I am getting two results; one for the variables declared (which I am not interested in having them as output), and the WITH statement that is selected at the end (which as the results that I am interested in).
The principal problem is that, whenever I try t connect this scheduled query to a table in Google Data Studio I get the following error:
Invalid value: configuration.query.destinationTable cannot be set for scripts;
How can I declare a variable without getting it as a result at the end?
Here you have a sample of the code I am trying work in:
DECLARE initial, final DATE;
SET initial = DATE_TRUNC(DATE_TRUNC(CURRENT_DATE(), MONTH)+7,ISOWEEK);
SET final = LAST_DAY(DATE_TRUNC(CURRENT_DATE(), MONTH)+7, ISOWEEK);
WITH HelloWorld AS (
SELECT shop_date, revenue
FROM fulltable
WHERE shop_date >= initial
AND shop_date <= final
)
SELECT * from HelloWorld;
with initial1 as ( select DATE_TRUNC(DATE_TRUNC(CURRENT_DATE(), MONTH)+7,ISOWEEK) as initial2),
final1 as ( select LAST_DAY(DATE_TRUNC(CURRENT_DATE(), MONTH)+7, ISOWEEK) as final2),
HelloWorld AS (
SELECT shop_date, revenue
FROM fulltable
WHERE shop_date >= (select initial2 from initial1) AND shop_date <= (select final2 from final1)
)
SELECT * from HelloWorld;
With config table having just 1 row and cross-joining it with your table, your query can be written like below.
WITH config AS (
SELECT DATE_TRUNC(DATE_TRUNC(CURRENT_DATE(), MONTH)+7,ISOWEEK) AS initial,
LAST_DAY(DATE_TRUNC(CURRENT_DATE(), MONTH)+7, ISOWEEK) AS final
),
HelloWorld AS (
SELECT * FROM UNNEST([DATE '2022-06-06']) shop_date, config
WHERE shop_date >= config.initial AND shop_date <= config.final
)
SELECT * FROM HelloWorld;
A few patterns I've used:
If you have many that have the same return type (STRING)
CREATE TEMP FUNCTION config(key STRING)
RETURNS STRING AS (
CASE key
WHEN "timezone" THEN "America/Edmonton"
WHEN "something" THEN "Value"
END
);
Then use config(key) to retrieve the value.
Or,
Create a function for each constant
CREATE TEMP FUNCTION timezone()
RETURNS STRING AS ("America/Edmonton");
Then use timezone() to get the value.
It would execute the function each time, so don't do something expensive in there (like SELECT from another table).

Need help to understand the SUM(CASE part of a query

I need a little help to understand understanding a SUM(CASE issue, mainly this section: THEN c.quantity * dbo.Get_Qty_Sum(c.Schedule_ref, c.Schedule_Line, c.master_part) END).
Here's the query :
SUM(CASE WHEN c.component LIKE '52-%' THEN c.quantity * dbo.Get_Qty_Sum(c.Schedule_ref, c.Schedule_Line, c.master_part) END) AS Ref_Qty
The scalar function, dbo.Get_Qty_Sum expects 3 parameters to be passed (c.Schedule_ref, c.Schedule_Line, c.master_part). The 3 values are taken in and then a single value is returned as shown in the example below:
CREATE FUNCTION [dbo].[Get_Qty_Sum]( #schedule_ref int, #schedule_line int, #master_part )
RETURNS INT
AS
BEGIN
RETURN #schedule_ref + #schedule_line + #master_part
END

Leading 0 on int Column problem SQL Server

I have an issue where I am trying to add a leading 0 to run an output.
SELECT
CASE
WHEN LEN(t.trans_time) = 5
THEN CONCAT(0, [trans_time])
ELSE T.[trans_time]
END AS [TransactionTime]
,RIGHT(CONCAT(0,trans_time),6) AS trans_time
,LEN(T.trans_Time)
,t.trans_time
Why does the case statement not return the leading 0 whereas using:
,RIGHT(CONCAT(0,trans_time),6) AS trans_time
Works no problem.
Case expression return only one type, whereas concat() would return different type & i am assuming trans_time has INT type.
So, you would need to do type conversations :
SELECT (CASE WHEN LEN(t.trans_time) = 5
THEN CONCAT(0, [trans_time])
ELSE CAST(T.[trans_time] AS VARCHAR(255))
END) AS [TransactionTime],
. . .
Another way to do this is to use the format function, wich is available from sql server 2012.
It not only makes the code more readable but will also perform better.
declare #t table (id int)
insert into #t values (90113), (90204), (90207), (90235), (90302), (90318), (90324)
select format(id, '000000') as TransactionTime from #t
this will return
TransactionTime
---------------
090113
090204
090207
090235
090302
090318
090324

Error creating function in DB2 with params

I have a problem with a function in db2
The function finds a record, and returns a number according to whether the first and second recorded by a user
The query within the function is this
SELECT
CASE
WHEN NUM IN (1,2) THEN 5
ELSE 2.58
END AS VAL
FROM (
select ROW_NUMBER() OVER() AS NUM ,s.POLLIFE
from LQD943DTA.CAQRTRML8 c
INNER JOIN LSMODXTA.SCSRET s ON c.MCCNTR = s.POLLIFE
WHERE s.NOEMP = ( SELECT NOEMP FROM LSMODDTA.LOLLM04 WHERE POLLIFE = '0010111003')
) AS T WHERE POLLIFE = '0010111003'
And works perfect
I create the function with this code
CREATE FUNCTION LIBWEB.BNOWPAPOL(POL CHAR)
RETURNS DECIMAL(7,2)
LANGUAGE SQL
NOT DETERMINISTIC
READS SQL DATA
RETURN (
SELECT
CASE
WHEN NUM IN (1,2) THEN 5
ELSE 2.58
END AS VAL
FROM (
select ROW_NUMBER() OVER() AS NUM ,s.POLLIFE
from LQD943DTA.CAQRTRML8 c
INNER JOIN LSMODXTA.SCSRET s ON c.MCCNTR = s.POLLIFE
WHERE s.NOEMP = ( SELECT NOEMP FROM LSMODDTA.LOLLM04 WHERE POLLIFE = POL)
) AS T WHERE POLLIFE = POL
)
The command runs executed properly
WARNING: 17:55:40 [CREATE - 0 row(s), 0.439 secs] Command processed.
No rows were affected
When I want execute the query a get a error
SELECT LIBWEB.BNOWPAPOL('0010111003') FROM DATAS.DUMMY -- dummy has only one row
I get
[Error Code: -204, SQL State: 42704] [SQL0204] BNOWPAPOL in LIBWEB
type *N not found.
I detect, when I remove the parameter the function works fine!
With this code
CREATE FUNCTION LIBWEB.BNOWPAPOL()
RETURNS DECIMAL(7,2)
LANGUAGE SQL
NOT DETERMINISTIC
READS SQL DATA
RETURN (
SELECT
CASE
WHEN NUM IN (1,2) THEN 5
ELSE 2.58
END AS VAL
FROM (
select ROW_NUMBER() OVER() AS NUM ,s.POLLIFE
from LQD943DTA.CAQRTRML8 c
INNER JOIN LSMODXTA.SCSRET s ON c.MCCNTR = s.POLLIFE
WHERE s.NOEMP = ( SELECT NOEMP FROM LSMODDTA.LOLLM04 WHERE POLLIFE = '0010111003')
) AS T WHERE POLLIFE = '0010111003'
)
Why??
This statement:
SELECT LIBWEB.BNOWPAPOL('0010111003') FROM DATAS.DUMMY
causes this error:
[Error Code: -204, SQL State: 42704] [SQL0204] BNOWPAPOL in LIBWEB
type *N not found.
The parm value passed into the BNOWPAPOL() function is supplied as a quoted string with no definition (no CAST). The SELECT statement assumes that it's a VARCHAR value since different length strings might be given at any time and passes it to the server as a VARCHAR.
The original function definition says:
CREATE FUNCTION LIBWEB.BNOWPAPOL(POL CHAR)
The function signature is generated for a single-byte CHAR. (Function definitions can be overloaded to handle different inputs, and signatures are used to differentiate between function versions.)
Since a VARCHAR was passed from the client and only a CHAR function version was found by the server, the returned error fits. Changing the function definition or CASTing to a matching type can solve this kind of problem. (Note that a CHAR(1) parm could only correctly handle a single-character input if a value is CAST.)

Arithmetic overflow error converting expression to data type float

Working on an analysis of bonds. I have attempted to make a payment function that replicates the PMT function of excel. For the bonds, the "Cusip" is their identifier, their "PASS THRU RATE" is their annual interest rate, the "ORIGINAL WA MATURITY" is the total number of periods, and the "ORIGINAL BALANCE" is the original face value of the bond.
The equation for calculating a monthly payment by paper is:
M=[OF(i(1+i)^n)]/[(1+i)^(n-1)]
M=Monthly payment
OF=Original Face
i=annual interest rate/12
n=number of periods
I have a table with all the columns needed for this function, as well as different tables for different months that I will try and use this for. This is what I have so far, creating the function and trying to fix for data types:
if object_id('dbo.PMT') > 0
drop function dbo.PMT
go
create function dbo.PMT(#rate numeric(15,9), #periods smallint, #principal numeric(20,2) )
returns numeric (38,9)
as
begin
declare #pmt numeric (38,9)
select #pmt = #principal
/ (power(1+#rate,#periods)-1)
* (#rate*power(1+#rate,#periods))
return #pmt
end
go
drop function dbo.PMT
go
create function dbo.PMT
(
#rate float,
#periods smallint,
#principal numeric(20,2)
)
returns numeric (38,9)
as
begin
declare #pmt numeric (38,9)
declare #WK_periods float,
#WK_principal float,
#wk_One float,
#WK_power float
select #WK_periods = #periods,
#WK_principal = #principal,
#WK_One = 1
select #pmt =
round(
( #WK_principal * (#rate*power(#WK_One+#rate,#WK_periods)))
/ (power(#WK_One+#rate,#WK_periods)-#WK_One)
,9)
return #pmt
end
go
select ALL [CUSIP NUMBER]
,[PASS THRU RATE]
,[ORIGINAL WA MATURITY]
,[ORIGINAL BALANCE],
dbo.pmt((mbs012013.[PASS THRU RATE]),mbs012013.[ORIGINAL WA MATURITY],mbs012013.[ORIGINAL BALANCE])
FROM
[MBS_STATS].[dbo].[mbs012013]
However, I receive
(502882 row(s) affected)
Msg 8115, Level 16, State 2, Line 2
Arithmetic overflow error converting expression to data type float.
when I attempt to execute it. I cannot figure out what is causing this. Any help would be great!
In the line below, you have #WK_principal as a FLOAT, and you're assigning the value of #principal which is a NUMERIC(20,2).
#WK_principal = #principal,
That seems to be the most likely culprit. We'd need to be able to see your data to help otherwise. Also, I'm not clear on why you're creating the function one way, then dropping it and recreating it differently. Or are you just showing two different attempts?