I am creating a Snowflake SQL UDF. I keep running into SQL compilation error: Unsupported subquery type cannot be evaluated. I have tried to do several things to go around the issue, this being my latest try.
How can I make this break out of the subquery'ing error?
The UDF should allow one to input their preferred year. Thinking to create a solution by if a year is not provided, the default would be the present year.
create or replace function new_value(PRICE float, TYPE varchar, YR_CREATED int, YEAR int)
returns float
as
$$
with AGE_OF_PRODUCT as (
select any_value((YEAR - YR_CREATED)) as AGE ),
FORMULA as (
select any_value(AGE) as AGE,
any_value(case
when AGE <= 1 then 1
else 2
end) as FUNCTION
from AGE_OF_PRODUCT
)
select
any_value(case
when F.FUNCTION = 1 then (PRICE - (PRICE * R.R1))
else (PRICE * (1 - (R.R1))) * pow((1-(R.R2)), ((F.AGE - YR_CREATED)-1))
end) as VALUE
from FORMULA as F, RATES as R
where TYPE = R.TYPE_OF_PRODUCT
$$;
So the main problem is you are likely using the function like:
select v.*,
new_value(v.price, v.type, v.yr_create, v.year) as awesome
from table_with_values as v
also your UDF can be rewritten as it stands as:
create or replace function new_value(
PRICE float,
TYPE varchar,
YR_CREATED int,
YEAR int)
returns float
as
$$
select
YEAR - YR_CREATED as age,
case age <= 1
when true then (PRICE - (PRICE * r.r1))
else (PRICE * (1 - (r.r1))) * pow((1-(r.r2)), ((age - YR_CREATED)-1))
end as value
from rates as r
where TYPE = r.type_of_product
$$;
but if we move the join to rates outside the UDF
create or replace function new_value(
PRICE float,
YR_CREATED int,
YEAR int,
rate1 float,
rate2 float)
returns float
as
$$
select
case (YEAR - YR_CREATED) <= 1
when true then (PRICE - (PRICE * r.r1))
else (PRICE * (1 - (rate1))) * pow((1-(rate2)), (((YEAR - YR_CREATED) - YR_CREATED)-1))
end as value;
$$;
then we can call it like:
select v.*,
new_value(v.price, v.yr_create, v.year, r.r1, r.r2) as awesome
from table_with_values as v
join rates as r
on v.type = r.type_of_product
Related
I'm trying to write a stored procedure that will return the results of a complex query:
CREATE OR REPLACE PROCEDURE sp_partition_ohlc(symbol VARCHAR(10),
from_time NUMERIC(20, 0),
til_time NUMERIC(20, 0),
step_time NUMERIC(20, 0))
RETURNS TABLE()
LANGUAGE SQL
AS
$$
BEGIN
SELECT
:step_time * bucket AS t,
SUM(T.volume) AS v,
MAX(T.open) AS o,
MAX(T.close) AS c,
MAX(T.highlow) AS h,
MIN(T.highlow) AS l,
v * (h + l + c) / 3 AS wv,
COUNT(*) AS n
FROM (
SELECT
FLOOR(T.sip_timestamp / :step_time) AS bucket,
cta_calc(T.size, T.conditions, 'VOLUME') AS volume,
cta_calc(T.price, T.conditions, 'HIGHLOW') AS highlow,
IFF(ROW_NUMBER() OVER (PARTITION BY bucket ORDER BY T.sip_timestamp) = 1, T.price, NULL) AS open,
LAST_VALUE(cta_calc(T.price, T.conditions, 'LAST'))
IGNORE NULLS OVER (PARTITION BY bucket ORDER BY T.sip_timestamp) AS close
FROM trades AS T
WHERE
T.symbol = :symbol AND
T.sip_timestamp >= :from_time AND
T.sip_timestamp < :til_time) AS T
GROUP BY bucket
ORDER BY bucket;
END
$$
This compiles properly but, if I try to run it:
CALL sp_partition_ohlc('NTAP', 1640995200000000000, 1672531200000000000, 3600000000000)
I get the following error:
092222 (P0000): SQL compilation error: stored procedure is missing a return statement
From this, I understand that I should have a RETURN in front of my outer SELECT statement. However, when I modify the procedure thus, it fails to compile with this error:
Syntax error: unexpected 'SELECT'. (line 7)
syntax error line 4 at position 23 unexpected '*'. (line 7)
I'm not sure what this error is telling me as, when I run the query by itself, it returns results. I assume I'm doing something wrong in setting up the procedure but I'm not sure what it is from the associated documentation, here. Any help would be appreciated.
It is not a matter of just putting a return in there:
you more want to follow a pattern like:
create or replace procedure get_top_sales()
returns table (sales_date date, quantity number)
language sql
as
declare
res resultset default (select sales_date, quantity from sales order by quantity desc limit 10);
begin
return table(res);
end;
here the res is a declared as the result set, which is the SQL to run, so you can access those, and then it is returned as a table via table(res) and the type of the res matches the return type of the function returns table (sales_date date, quantity number), so for your function you would need to alter this also.
so something like (I have not run):
CREATE OR REPLACE PROCEDURE sp_partition_ohlc(symbol VARCHAR(10),
from_time NUMERIC(20, 0),
til_time NUMERIC(20, 0),
step_time NUMERIC(20, 0))
RETURNS TABLE(t int, v float, o float, c float, h float, l float, wv float, n int) /* guessed types */
LANGUAGE SQL
AS
$$
DECLARE
res resultset;
BEGIN
let res := (
SELECT
:step_time * bucket AS t,
SUM(T.volume) AS v,
MAX(T.open) AS o,
MAX(T.close) AS c,
MAX(T.highlow) AS h,
MIN(T.highlow) AS l,
v * (h + l + c) / 3 AS wv,
COUNT(*) AS n
FROM (
SELECT
FLOOR(T.sip_timestamp / :step_time) AS bucket,
cta_calc(T.size, T.conditions, 'VOLUME') AS volume,
cta_calc(T.price, T.conditions, 'HIGHLOW') AS highlow,
IFF(ROW_NUMBER() OVER (PARTITION BY bucket ORDER BY T.sip_timestamp) = 1, T.price, NULL) AS open,
LAST_VALUE(cta_calc(T.price, T.conditions, 'LAST'))
IGNORE NULLS OVER (PARTITION BY bucket ORDER BY T.sip_timestamp) AS close
FROM trades AS T
WHERE
T.symbol = :symbol AND
T.sip_timestamp >= :from_time AND
T.sip_timestamp < :til_time) AS T
GROUP BY bucket
ORDER BY bucket
);
return table(res);
END
$$
I am using PostgreSql and I am new to stored functions. I want my stored function to return multiple columns.
The following inputs reflects the columns of the original table, which stores data from different users (e.g. clicks_a, clicks_b, clicks_c, cost_a, cost_b, cost_c etc.).
Input: clicks, cost, bookings, booking_rev
Desidered output:
month | ttt_group | cpc | monthly_clicks_mln | cvr | margin_per_conversion | monthly_profit | break_even_cpc | ideal_ccp
I wrote the following code, but I am getting this error:
ERROR: The reference to the "market_segment" column is ambiguous.
Code:
CREATE OR REPLACE FUNCTION user_performance
(clicks CHARACTER VARYING, cost CHARACTER VARYING,
bookings CHARACTER VARYING, booking_rev CHARACTER VARYING)
RETURNS table(month DOUBLE PRECISION, market_segment CHARACTER VARYING,
cpc TEXT, monthly_clicks_mln NUMERIC(10,3), cvr TEXT,
margin_per_conversion TEXT, monthly_profit MONEY, break_even_cpc TEXT, ideal_ccp TEXT)
AS $BODY$
BEGIN
WITH monthly_activity AS (
SELECT EXTRACT(MONTH FROM date) AS month, market_segment,
CASE WHEN clicks = 'clicks_a' THEN SUM(clicks_a)
WHEN clicks = 'clicks_b' THEN SUM(clicks_b)
WHEN clicks = 'clicks_c' THEN SUM(clicks_c)
END AS monthly_clicks,
CASE WHEN cost = 'cost_a' THEN SUM(cost_a)
WHEN cost = 'cost_a' THEN SUM(cost_b)
WHEN cost = 'cost_a' THEN SUM(cost_c)
END AS monthly_cost,
CAST(CASE WHEN cost = 'cost_a' AND clicks = 'clicks_a'
THEN (SUM(cost_a) :: FLOAT /SUM(clicks_a) :: FLOAT)
WHEN cost = 'cost_b' AND clicks = 'clicks_b'
THEN (SUM(cost_b) :: FLOAT /SUM(clicks_b) :: FLOAT)
WHEN cost = 'cost_c' AND clicks = 'clicks_c'
THEN (SUM(cost_c) :: FLOAT /SUM(clicks_c) :: FLOAT)
END AS DECIMAL(5,4)) AS cpc,
CASE WHEN bookings = 'bookings_a' THEN SUM(bookings_a)
WHEN bookings = 'bookings_b' THEN sum(bookings_b)
WHEN bookings = 'bookings_c' THEN sum(bookings_c)
END AS monthly_bookings,
CASE WHEN booking_rev = 'booking_rev_a' THEN SUM(booking_rev_a)*15/100
WHEN booking_rev = 'booking_reb_b' THEN SUM(booking_rev_b)*15/100
WHEN booking_rev = 'booking_reb_c' THEN SUM(booking_rev_c)*15/100
END AS monthly_margin
FROM master_table_2019
GROUP BY month, market_segment
ORDER BY month
),
adv_metrics AS (
SELECT
month,market_segment,
CAST(AVG(cpc) AS DECIMAL(10,3)) AS cpc,
CAST(AVG(monthly_clicks)/1000000.0 AS DECIMAL(10,3)) AS monthly_clicks_mln,
CAST(MAX(100.0*monthly_bookings :: FLOAT /monthly_clicks :: FLOAT) AS DECIMAL(3,2)) AS cvr,
CAST(AVG(monthly_margin :: FLOAT /monthly_bookings :: FLOAT) AS DECIMAL(10,3)) AS margin_per_conversion,
MAX(monthly_margin - monthly_cost) AS monthly_profit
FROM monthly_activity
GROUP BY month, market_segment
ORDER BY month
)
SELECT
month, market_segment,
CONCAT(cpc,' €') AS cpc,
monthly_clicks_mln,
CONCAT(cvr,'%') AS cvr,
CONCAT(margin_per_conversion,' €') AS margin_per_conversion,
MONEY(monthly_profit) AS monthly_profit,
CONCAT(CAST((margin_per_conversion * cvr/100.0) AS DECIMAL(4,3)),' €') AS break_even_cpc,
CONCAT(CAST((margin_per_conversion * cvr/100.0)*0.85 AS DECIMAL(4,3)),' €') AS ideal_ccp
FROM adv_metrics
ORDER BY month, market_segment;
END;
$BODY$ LANGUAGE plpgsql;
SELECT * FROM user_performance('clicks_a', 'cost_a', 'bookings_a', 'booking_rev_a')
How can I fix this code and make it works?
How can I chance custno: 5.0256926E7 into a normal integer / number in Impala SQL?
This is what I've tried so far:
SELECT * FROM z9_strategy.dstool_model_data_m
WHERE snapshot_date_key = 20170630
AND custtype_ind = 1
AND retailer_retail = 1
AND CAST((custno AS FLOAT) AS int);
I also tried SELECT CAST(CAST(custno AS FLOAT) AS int)
Use CAST:
CAST(custno AS int);
I need idea for sql select on this.
I have a table with this columns:
ID type quan price
1 1 5 6.5
1 1 4 7
1 2 5 10
1 1 5 6
I need to run a query with following condition:
fir i = 1 to 4
if type = 1
rprice = (rprice*rquan + price*quan)/(rquan+quan)
rquan = rquan + quan
else
rquan = rquan - quan
end
next
The type can be 1 or 2
For ID 1 I need as result rquan and rprice
The sumary result must be :
rquan=9 rprice=6.32
select
case when type = 1
then (rprice*rquan + price*quan)/(rquan+quan)
else price
end as "rprice"
,case when type = 1
then rquan + quan
else quan
end as "rquan"
from "table_name"
Assuming you have a column that specifies the ordering of the rows, you can do this with cumulative sums and/or aggregation. For instance, for rquan:
select rquan
from (select t.*,
sum(case when type = 1 then quan else - quan end) over (order by ??) as rquan_row
from table t
) t
order by ?? desc
limit 1;
This can actually be simplified to a single conditional aggregation, but you seem to want this quantity row-by-row.
I don't fully understand the calculation for rprice. I can see what the formula is, but it doesn't make sense. An average price for the data would be 6 not 6.32.
You can write a custom aggregate to do this. The syntax is rather strange in places, though.
create schema so32264410;
create table so32264410.data(seqno serial primary key, id int, type int, quan int, price numeric);
insert into so32264410.data(id, type, quan, price) values(1, 1, 5, 6.5),(1, 1, 4, 7),(1, 2, 5, 10),(1, 1, 5, 6);
-- define a type to hold the aggregation and a function to perform reduction
create type so32264410.calc_type as (quan int, price numeric);
create function so32264410.calc_sfunc(state so32264410.calc_type, type int, quan int, price numeric) returns so32264410.calc_type immutable language plpgsql as $$
declare
rquan int;
rprice numeric;
begin
rquan := state.quan;
rprice := state.price;
if type = 1 then
rprice := (rprice * rquan + price * quan) / (rquan + quan);
rquan := rquan + quan;
else
rquan := rquan - quan;
end if;
state := row(rquan, rprice)::so32264410.calc_type;
return state;
end
$$;
-- bind the reducing function, state type and initial state into an aggregate
create aggregate so32264410.calc(int, int, numeric) (sfunc = so32264410.calc_sfunc, stype = so32264410.calc_type, initcond = '(0,0)');
select so32264410.calc(type, quan, price) from so32264410.data where id = 1;
I was trying to create a function which returns to an integer. However, I got the warning as
"Msg 2715, Level 16, State 3, Procedure median, Line 1
Column, parameter, or variable #0: Cannot find data type Median."
Here is the query. Thanks in advance.
CREATE FUNCTION dbo.median (#score int)
RETURNS Median
AS
BEGIN
DECLARE #MedianScore as Median;
SELECT #MedianScore=
(
(SELECT MAX(#score) FROM
(SELECT TOP 50 PERCENT Score FROM t ORDER BY Score) AS BottomHalf)
+
(SELECT MIN(#score) FROM
(SELECT TOP 50 PERCENT Score FROM t ORDER BY Score DESC) AS TopHalf)
) / 2 ;
RETURN #MedianScore;
END;
GO
Just change the return type to integer:
CREATE FUNCTION dbo.median (#score int)
RETURNS integer
AS
BEGIN
DECLARE #MedianScore as integer;
Unless you're intentionally using the Median type for something that you haven't stated.
Since you are calculating Median of some values I would suggest you return a Numeric value instead of Integer as MAX(#score) + MIN(#score)/ 2 can return a decimal number value. so trying to save that value in an INT variable will truncate the Decimal part. which can lead to wrong results.
In the following example I have used NUMERIC(20,2) return value.
CREATE FUNCTION dbo.median (#score int)
RETURNS NUMERIC(20,2)
AS
BEGIN
DECLARE #MedianScore as NUMERIC(20,2);
SELECT #MedianScore=
(
(SELECT MAX(#score) FROM
(SELECT TOP 50 PERCENT Score FROM t ORDER BY Score) AS BottomHalf)
+
(SELECT MIN(#score) FROM
(SELECT TOP 50 PERCENT Score FROM t ORDER BY Score DESC) AS TopHalf)
) / 2 ;
RETURN #MedianScore;
END;
GO
or if you do want to return an INTEGER use round function inside the function something like this..
CREATE FUNCTION dbo.median (#score int)
RETURNS INT
AS
BEGIN
DECLARE #MedianScore as INT;
SELECT #MedianScore=ROUND(
(
(SELECT MAX(#score) FROM
(SELECT TOP 50 PERCENT Score FROM t ORDER BY Score) AS BottomHalf)
+
(SELECT MIN(#score) FROM
(SELECT TOP 50 PERCENT Score FROM t ORDER BY Score DESC) AS TopHalf)
) / 2, 0) ;
RETURN #MedianScore;
END;
GO
You must declare a datatype on RETURNS. "Median" is not a type.
CREATE FUNCTION dbo.median (#score int)
RETURNS real -- you can use also float(24), numeric(8,3), decimal(8,3)...
AS
BEGIN
DECLARE #MedianScore as real;
SELECT #MedianScore=
(
(SELECT MAX(#score) FROM
(SELECT TOP 50 PERCENT Score FROM t ORDER BY Score) AS BottomHalf)
+
(SELECT MIN(#score) FROM
(SELECT TOP 50 PERCENT Score FROM t ORDER BY Score DESC) AS TopHalf)
) / 2 ;
RETURN #MedianScore;
END;
GO
create function [dbo].[Sum]
(
#x int,
#y int
)
RETURNS int
AS
BEGIN
return #x+#y
END