3

When creating functions, I tend to preface the creation with an existence check

IF Object_ID(N'myfunc', N'IF') IS NOT NULL 
DROP FUNCTION myfunc

GO
CREATE FUNCTION myfunc...

There are several types of object_id to be checked for functions :

FN = SQL scalar function
IF = SQL inline table-valued function
TF = SQL table-valued-function
FT = Assembly (CLR) table-valued function

I have some questions :

  1. What is the difference between 'IF', 'TF' and 'FT' type ?

  2. It is very error-prone to use

    IF Object_ID(N'myFunc', 'IF') IS NOT NULL
    

    as sometime the function is scalar, other cases it is table-valued etc. so I may miss the correct type check.

I see people recommending

IF EXISTS (SELECT * FROM sys.objects 
WHERE object_id = OBJECT_ID(N'myfunc') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))

Will it suffice for checking all type of functions ? What is your recommendation ?

Kenny
  • 1,902
  • 6
  • 32
  • 61

2 Answers2

5

1) IF vs multiline TF vs CLR TF

Inline Table Valued Function

Acts like macro, very efficient can be treated like parametrized view

CREATE FUNCTION dbo.name(@param INT)
RETURNS TABLE
AS 
RETURN 
   SELECT ...
   FROM tab t
   WHERE t.Col = @param;
GO

Multi Statement Table Valued Function

More flexible you can do many intermediate steps if needed but it will be slower than IF.

CREATE FUNCTION dbo.name()
RETURNS @Result TABLE
(Col_name    INT         NOT NULL,
...
)
AS
BEGIN
    /* Many operations */

    INSERT @Result
    SELECT *
    FROM ...

    RETURN
END
GO

CLR Table-Valued Functions

From MSDN

Transact-SQL table-valued functions materialize the results of calling the function into an intermediate table. Since they use an intermediate table, they can support constraints and unique indexes over the results. These features can be extremely useful when large results are returned.

In contrast, CLR table-valued functions represent a streaming alternative. There is no requirement that the entire set of results be materialized in a single table. The IEnumerable object returned by the managed function is directly called by the execution plan of the query that calls the table-valued function, and the results are consumed in an incremental manner. This streaming model ensures that results can be consumed immediately after the first row is available, instead of waiting for the entire table to be populated. It is also a better alternative if you have very large numbers of rows returned, because they do not have to be materialized in memory as a whole. For example, a managed table-valued function could be used to parse a text file and return each line as a row.

2) Checking if function exists:

Check ROUTINES catalog:

Returns one row for each stored procedure and function that can be accessed by the current user in the current database.

IF EXISTS ( SELECT  1
            FROM INFORMATION_SCHEMA.ROUTINES
            WHERE Specific_schema = 'dbo'
              AND specific_name = 'Foo'
              AND Routine_Type = 'FUNCTION' ) 
Lukasz Szozda
  • 162,964
  • 23
  • 234
  • 275
1

Add the schema name and remove the object type. Why do you need to check if the object is a function? Think this through:

if object_id(N'dbo.functionname') is not null
drop function dbo.functionname
go
create function dbo.functionname ...

... will drop the function if it exists, then create it.

If there is already an object named "dbo.functionname" and it is NOT a function, the drop will fail. But that's true whether or not you check that "dbo.functionname" is a function or not.

In other words, if there is a TABLE (or any other non-function object) named dbo.functionname, then

if object_id(N'dbo.functionname', N'IF') -- equates to false
drop function dbo.functionanme -- doesn't get run
go
create function dbo.functionname... -- generates error

would fail on the create function (because the table dbo.functionname would not be dropped).

You can't have two objects with the same schema.objectname. So if you just check for object_id(N'schema.objectname'), you should be fine.

Brian Stork
  • 945
  • 2
  • 8
  • 14