This is my code for Google BigQuery UDF.
CREATE OR REPLACE FUNCTION `my_dataset.ST_EXTENT_TABLE`
(tableName STRING)
RETURNS STRUCT<xmin FLOAT64, ymin FLOAT64, xmax FLOAT64, ymax FLOAT64>
AS (
WITH data AS ( SELECT geom FROM tableName)
SELECT ST_EXTENT(geom) AS box FROM data
);
In "SELECT geom FROM tableName", tableName should be replaced with passed value.
Any idea?
According to your requirement, it is not possible to dynamically pass the table name in UDF. As an alternative you can write a dynamic sql query where you can pass the table name dynamically. Using Execute Immediate you can execute those dynamic queries and get the result.
You can try the below sample query.
Query:
DECLARE query String;
SET
query = '''with cte as (
select filename from %s limit 10
)
select * from cte''';
EXECUTE IMMEDIATE
FORMAT(query,"bigquery-public-data.bbc_news.fulltext")
Output:
Related
I keep getting the error : "Parameters were not supplied" for a very simple table-valued function. I cannot figure out what is the issue. I narrowed the function down to :
create FUNCTION udf_XX_OddFCST()
RETURNS #output TABLE (
articlecode nvarchar(50)
)
AS
BEGIN
insert into #output(articlecode) values ('abc');
RETURN
END
So I get the error when executing
select * from udf_XX_OddFCST
Any help would be greatly appreciated.
kind regards
you need to use parentheses in your function call :
SELECT * FROM udf_XX_OddFCST()
however as it has been mentioned in the comments, it would be more simpler and more efficient using iTVF:
CREATE FUNCTION udf_XX_OddFCST()
RETURNS TABLE
AS
RETURN (select 'abc' as articlecode)
SELECT * FROM udf_XX_OddFCST()
I get a list of elments from R and I have to obtain the records from database that belong to a the list of elements.
INPUT:
'12345','23456', '34567', '45678'
PROCEDURE:
CREATE PROCEDURE "SCHEMA"."GET_RECORDS" (IN LIST (Type), OUT RECORDS tt_records)
LANGUAGE SQLSCRIPT
SQL SECURITY INVOKER
READS SQL DATA AS
BEGIN
RECORDS = select * from TABLE where ids in :LIST
END;
How can I provide such a list to the proceudre?
Handing over lists of parameters to SQLScript is a bit tricky as there is no straight-forward native construct for that.
One way to do it is to use the APPLY_FILTER function and to "smuggle" the list as a string parameter.
In my example I read from a table CUSERS and I create a filter condition for APPLY_FILTER that filters column USER_ID via an IN ( ) clause.
Removing the single quotes (' ') from the list is to avoid implicit type conversion when executing the query. Leaving the single quotes in place would make the IN () clause make look like this:
IN ( '<1st value>', '<2nd value>', '<3rd value>', ...)
instead of
IN (<1st value>, <2nd value>, <3rd value>, ...).
CREATE PROCEDURE "GET_RECORDS" (IN id_list VARCHAR(4000)
, OUT RECORDS tt_cusers)
LANGUAGE SQLSCRIPT
SQL SECURITY INVOKER
READS SQL DATA AS
BEGIN
declare _filter VARCHAR(4000);
_users = select * from cusers;
-- APPLY_FILTER expects a proper WHERE condition, so adding the column to filter
-- and the IN () expression is necessary.
--
-- the the id_list comes in with single quotes, let's remove those
_filter = 'USER_ID in (' || replace (:id_list, '''', '') ||')';
RECORDS = APPLY_FILTER(:_users, :_filter);
end;
call get_records (?, ?)
-- this 'list' is to be used as a single parameter value
-- '131072', '161223', '131074'
A slightly more comfortable approach for getting the data out from SAP HANA into R can be using a table typed user-defined function (UDF) instead. The main difference here is that the calling statement is a simple SELECT and the result is simply the resultset of this SELECT.
CREATE function "FGET_RECORDS" (IN id_list VARCHAR(4000))
returns tt_cusers
LANGUAGE SQLSCRIPT
SQL SECURITY INVOKER
READS SQL DATA AS
BEGIN
declare _filter VARCHAR(4000);
_users = select * from cusers;
-- APPLY_FILTER expects a proper WHERE condition, so adding the column to filter
-- and the IN () expression is necessary.
--
-- the the id_list comes in with single quotes, let's remove those
_filter = 'USER_ID in (' || replace (:id_list, '''', '') ||')';
_result = APPLY_FILTER(:_users, :_filter);
RETURN :_result;
end;
select * from fget_records (? );
In R (or in any other client) make sure to use bind variables when using this construct. Otherwise handling the different string quote-mechanisms can become cumbersome.
See the documentation on APPLY_FILTER here.
Use a User Defined Data Type.
First Create A User Defined Data Type
Database Node > Programmability > Types > User-Defined Table Types
Script :
CREATE TYPE dbo.MyTableType AS TABLE
(
ID INT
)
Create a Parameter in your procedure with the above type
CREATE PROCEDURE usp_InsertMessages
(
#MyParameter MyTableType READONLY
)
AS
BEGIN
INSERT INTO MyTable
(
id
)
SELECT
id
FROM #MyParameter
END
I know function name TestOptionalParameter and parameter name number.
parameter is optional and has default value, which can change later
the function is
CREATE FUNCTION TestOptionalParameter
(
#number int = 1
)
RETURNS TABLE
AS
RETURN
(
SELECT #number * #number as sqr
)
how can I get value 1 from another function (or stored procedure) in the same database?
UPDATE
basically I don't need the result of function (I can get it with select * from TestOptionalParameter(default));
I'm trying to know what is default value (1 in my example) and save it into variable (something like declare x int = dbo.GetDefaultValue('TestOptionalParameter', '#number'))
so I need equivalent of c# reflection (Can I retrieve default value of parameter in method?)
Based on your comment reply I think you want call function in another function with the current parameter value pass.
So I think, this example might work for you.
CREATE FUNCTION TestOptionalParameter
(
#number int = 1
)
RETURNS TABLE
AS
RETURN
(
SELECT #number * #number as sqr
)
CREATE FUNCTION TestOptionalParameterNew
(
#number int = 1
)
RETURNS TABLE
AS
RETURN
(
SELECT #number * #number as total from [dbo].[TestOptionalParameter](#number)
)
select * from TestOptionalParameterNew(4)
The only way to get the parameter value seems to be to parse the ROUTINE_DEFINITION column of the information_schema.routines view as apparently the value isn't stored in any column, but rather evaluated from the definition at runtime.
If you know the parameter name in advance and the text in the procedure is well-formed then something like this could work. Note that in this example the substring returned is only 1 character long, so if the value can be longer you would have to extract a longer string.
SELECT
SUBSTRING
(
routine_definition,
PATINDEX('%#number int = %', ROUTINE_DEFINITION) + 14,
1
) ParamValue
FROM information_schema.routines
WHERE routine_type = 'function' AND
routine_name = 'TestOptionalParameter'
If you don't know the parameter names they can be found in the view referenced above, so it should be possible to find all default values by parsing the text definition, although it won't be easy.
You can use the below query to get the details about function
SELECT * FROM information_schema.routines WHERE routine_type='function' AND routine_name ='TestOptionalParameter'
As far as I know, we can return a table as a result of a db function:
CREATE FUNCTION MyFunction(#Value varchar(100))
RETURNS table
AS RETURN (select * from MyTable where ColumnName = '#Value')
in this example we can make the column name as a parameter for the function. My question is, can we write the column name and table name as a parameter for the function? hence we can write a more generic function something like:
CREATE FUNCTION MyGenericSearchFunction(#TableName varchar(100), #ColumnName varchar(100), #Value varchar(100))
RETURNS table
AS RETURN (select * from #TableName where #ColumnName = '#Value')
No, you can't.
This would then be a dynamic query.
For dynamic queries in SQL Server, one has to use exec() or sp_executesql() functions, which are not allowed in functions.
I have the following MySQL routine:
DELIMITER $$
CREATE DEFINER=`root`#`%` PROCEDURE `getGroupOrders`(grp INT,
ord CHAR(20),
srt CHAR(4),
page INT,
count INT)
BEGIN
SELECT *
FROM `dbre`.`order_info`
WHERE username IN (SELECT `dbre`.`users`.`username`
FROM `dbre`.`users`
WHERE `dbre`.`users`.`id_group` = grp)
ORDER BY ord srt LIMIT page,count;
END
As you can see, I want to pass the ordering column and sorting as a parameters, however I get a syntax error is there a way to do this or do I have to make similar routines for each type of ordering?
I don't think this is possible in the way you try it.
You cannot use a variable to define the ORDER BY column an direction.
The only workaround I can think of is to create a prepared statement from a dynamically created string (where you can use the variables to specify the order by details) and then execute that prepared statement.
Here is an example of such a dynamic statement:
http://forums.mysql.com/read.php?98,393613,393642#msg-393642