Calling Scalar-valued Functions in SQL - sql

I have migrated a database from oracle, and now have a few Scalar-valued Functions.
However, when I call them, I get an error saying:
Cannot find either column "dbo" or the user-defined function or aggregate "dbo.chk_mgr", or the name is ambiguous.
I'm calling it like this:
SELECT dbo.chk_mgr('asdf')
What am I doing wrong?

Are you sure it's not a Table-Valued Function?
The reason I ask:
CREATE FUNCTION dbo.chk_mgr(#mgr VARCHAR(50))
RETURNS #mgr_table TABLE (mgr_name VARCHAR(50))
AS
BEGIN
INSERT #mgr_table (mgr_name) VALUES ('pointy haired boss')
RETURN
END
GO
SELECT dbo.chk_mgr('asdf')
GO
Result:
Msg 4121, Level 16, State 1, Line 1
Cannot find either column "dbo" or the user-defined function
or aggregate "dbo.chk_mgr", or the name is ambiguous.
However...
SELECT * FROM dbo.chk_mgr('asdf')
mgr_name
------------------
pointy haired boss

Can do the following
PRINT dbo.[FunctionName] ( [Parameter/Argument] )
E.g.:
PRINT dbo.StringSplit('77,54')

That syntax works fine for me:
CREATE FUNCTION dbo.test_func
(#in varchar(20))
RETURNS INT
AS
BEGIN
RETURN 1
END
GO
SELECT dbo.test_func('blah')
Are you sure that the function exists as a function and under the dbo schema?

You are using an inline table value function. Therefore you must use Select * From function.
If you want to use select function() you must use a scalar function.
https://msdn.microsoft.com/fr-fr/library/ms186755%28v=sql.120%29.aspx

Make sure you have the correct database selected. You may have the master database selected if you are trying to run it in a new query window.

Related

SQL Server table-valued function Parameters were not supplied for the function-

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()

Table Variables in Azure Data Warehouse

In a SQL Server database, one can use table variables like this:
declare #table as table (a int)
In an Azure Data Warehouse, that throws an error.
Parse error at line: 1, column: 19: Incorrect syntax near 'table'
In an Azure Data Warehouse, you can use temporary tables:
create table #table (a int)
but not inside functions.
Msg 2772, Level 16, State 1, Line 6 Cannot access temporary tables
from within a function.
This document from Microsoft says,
◦Must be declared in two steps (rather than inline): ◾CREATE TYPE
my_type AS TABLE ...; , then ◾DECLARE #mytablevariable my_type;.
But when I try this:
create type t as table (a int);
drop type t;
I get this :
Msg 103010, Level 16, State 1, Line 1 Parse error at line: 1, column:
8: Incorrect syntax near 'type'.
My objective is to have a function in an Azure Data Warehouse which uses a temporary table. Is it achievable?
Edit Start Here
Note that I am not looking for other ways to create one specific function. I have actually done that and moved on. I'm a veteran programmer but an Azure Data Warehouse rookie. I want to know if it's possible to incorporate some concept of temporary tables in an Azure Data Warehouse function.
Ok, I believe this is what you are after.
Firstly, this uses a Table Value Function, which are significantly faster than Scalar or Multi-statement Table value Functions.
Secondly, there was no use for a Table Variable, or Temporary Table, just some good odd string manipulation, a bit of maths, and a CTE. Definitely no expensive WHILE loop.
I've tested this against the examples in the link, and they all return the expected values.
USE Sandbox;
GO
CREATE FUNCTION ValidateHealthNumber (#HealthNumber varchar(10))
RETURNS TABLE
AS
RETURN
WITH Doubles AS(
SELECT CONVERT(tinyint,SUBSTRING(V.HN,O.P,1)) AS HNDigit,
CONVERT(tinyint,SUBSTRING(V.HN,O.P,1)) * CASE WHEN O.P % 2 = 0 THEN 1 ELSE 2 END ToAdd
FROM (VALUES(#HealthNumber)) V(HN)
CROSS APPLY (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9)) O(P)),
Parts AS (
SELECT CONVERT(tinyint,SUBSTRING(CONVERT(varchar(2),ToAdd),1,1)) AS FirstDigit, --We know that the highest value can be 18 (2*9)
CONVERT(tinyint,SUBSTRING(CONVERT(varchar(2),ToAdd),2,1)) AS SecondDigit --so no need for more than 2 digits.
FROM Doubles)
SELECT CASE RIGHT(#HealthNumber, 1) WHEN 10 - RIGHT(SUM(FirstDigit + SecondDigit),1) THEN 1 ELSE 0 END AS IsValid
FROM Parts;
GO
CREATE TABLE #Sample(HealthNumber varchar(10));
INSERT INTO #Sample
VALUES ('9876543217'), --Sample
('5322369835'), --Valid
('7089771195'), --Valid
('8108876957'), --Valid
('4395667779'), --Valid
('6983806917'), --Valid
('2790412845'), --not Valid
('5762696912'); --not Valid
SELECT *
FROM #Sample S
CROSS APPLY ValidateHealthNumber(HealthNumber) VHN;
GO
DROP TABLE #Sample
DROP FUNCTION ValidateHealthNumber;
If you don't understand any of this, please do ask.
No you can't. Object can't be created inside User Defined Functions (UDF). Use table variables instead.
If you want yo use user defined type, first create it outside the UDF and use it as a variable type within the UDF.
-- Create the data type
CREATE TYPE TestType AS TABLE
(
Id INT NOT NULL,
Col1 VARCHAR(20) NOT NULL)
GO
-- Create the tabled valued function
CREATE FUNCTION TestFunction
()
RETURNS
#Results TABLE
(Result1 INT, Result2 INT)
AS
BEGIN
-- Fill the table variable with the rows for your result set
DECLARE #Var1 TestType;
RETURN
END
GO

Getting error while running function using T-SQL

I have created small table value function using T-SQL which takes one input parameter phone number as and returns area code from it. Function compiles successfully but when I run it I am getting error:
Msg 4121, Level 16, State 1, Line 1776
Cannot find either column "dbo" or the user-defined function or aggregate "dbo.getareacode1", or the name is ambiguous
Refer to my code:
create or alter function dbo.getareacode1 (#phoneno as nvarchar(20))
returns table
with schemabinding
as
return
(select top 1
#phoneno as PhoneNumber, value as AreaCode
from
string_split(#phoneno,'-')
);
select dbo.getareacode1( N'323-234-2111');
First off, the order of the rows returned from STRING_SPLIT is not guaranteed, so this function broken to begin with.
But the error is caused by trying to invoke a Table-Valued Function where a scalar is expected.
A TVF cannot be treated like a scalar function. So
create or alter function dbo.getareacode1 (#phoneno as nvarchar(20))
returns table
with schemabinding
as
return
(
select top 1 #phoneno as PhoneNumber, value as AreaCode
from string_split(#phoneno,'-')
);
go
select * from dbo.getareacode1( N'323-234-2111');
And if you want to call it from another query use CROSS APPLY, eg
with phoneNumbers as
(
select N'323-234-2111' phoneno
from sys.objects
)
select ac.*
from phoneNumbers p
cross apply dbo.getareacode1(p.phoneno) ac;
On the flip-side of what David said: for your function to work like you were expecting you will need a scalar user-defined function (udf). This function:
-- Create function
create or alter function dbo.getareacode1 (#phoneno as nvarchar(20))
returns nvarchar(20) with schemabinding as
begin
return
(
select top (1) AreaCode = ss.[value]
from string_split(#phoneno,'-') ss
);
end
GO
... will allow this query to work:
select dbo.getareacode1( N'323-234-2111');
All that said, I strongly advise against using scalar udfs. I'll include a a couple good links that explain why at the bottom of this post. Leaving your function as-is and using APPLY, as David demonstrated, is the way to go. Also, string_split is not required here. If phone numbers are always coming in this format: NNN-NNN-NNNN, you could just use SUBSTRING:
SUBSTRING(N'323-234-2111', 1, 3).
For countries with varible-length area codes in the format (area code(2 or more digits))-NNN-NNNN you could do this:
declare #phoneno nvarchar(30) = N'39-234-2111'; -- Using a variable for brevity
select substring(#phoneno,1, charindex('-',#phoneno)-1);
If you, for whatever reason, really need a function, then this is how I'd write it:
-- using the variable-length requirement as an example
create or alter function dbo.getareacode1_itvf(#phoneno as nvarchar(20))
returns table with schemabinding as
return (select areacode = substring(#phoneno,1, charindex('-',#phoneno)-1));
go
Great articles about Scalar UDFs and why iTVFs are better:
How to Make Scalar UDFs Run Faster -- Jeff Moden
Scalar functions, inlining, and performance -- Adam Machanic
TSQL Scalar functions are evil – Andy Irving -- Stackoerflow post

MonetDB Prepare Statement in Function

I'm trying to create a function that takes the parameters for the column, the table, the limit, and offset. Basically, I want to be able to get a specified number of rows data from a specified table from a specified column.
However, I'm unable to get the following code to work - I get several errors such as:
syntax error, unexpected SELECT, expecting ':' in: "create function get_banana(lim int, off int, tbl varchar(32), col varchar(32)) r"
syntax error, unexpected RETURN in: "return"
syntax error, unexpected END in: "end"
These errors seem kind of meaningless.
My code is as follows:
CREATE FUNCTION GET_BANANA(lim int, off int, tbl varchar(32), col varchar(32))
RETURNS TABLE (clm int)
BEGIN
PREPARE SELECT col FROM tbl LIMIT ? OFFSET ?;
RETURN EXEC (lim, off);
END;
I'd appreciate any help :) Thanks!
I see at least two issues
EXEC needs the identifier that is returned by PREPARE, e.g.:
sql>prepare select * from tables;
execute prepared statement using: EXEC 2(...)
sql>exec 2();
The function parameters tbl and col are string values. You cannot use them as table/column identifiers.
Having said that, I am not even sure if PREPARE can be used inside a function.
No, PREPARE is a top-level statement modifier.

Using SYSTEM_USER as a parameter to a table valued function

I've created a table valued function:
CREATE FUNCTION TestFunction
(
#username VARCHAR(80)
)
RETURNS TABLE
AS
RETURN
(
SELECT 0 AS TestValue
)
Then try to call it as so:
SELECT TestValue
FROM dbo.TestFunction(SYSTEM_USER)
but get the error:
Incorrect syntax near the keyword 'SYSTEM_USER'
I've even tried making this a table valued function which is not inline, but I get the same error.
Am I missing something? Why am I getting this error?
On my 2k8 server I can only reproduce that with SQL Server 2000 (80) Compatibility level set, check the level of your 2005 database.
Meantime you can;
declare #su varchar(30) = SYSTEM_USER
select * from dbo.TestFunction(#su)