User Defined Function - using table name as variable

  • Hello everyone-

    I'm trying to create a simple function that will do a count on a table. I want to pass the table name in form of a parameter to the variable and this function will return the count as an int. Please see my function below and help me understand why this is not working.

    CREATE FUNCTION count_rows (@tablename varchar(100)

    RETURNS int AS

    BEGIN

    DECLARE @emp_count AS int

    declare @declaration varchar(100)

    @declaration='SELECT count(*) FROM ' + @tablename

    @emp_count=cast(@declaration as int)

    --dbo.TD_EmployeeProfile_FinalV2

    RETURN @emp_count

    END

    GO

    The errors I am getting are as follows:

    Msg 102, Level 15, State 1, Procedure count_rows, Line 3

    Incorrect syntax near 'RETURNS'.

    Msg 102, Level 15, State 1, Procedure count_rows, Line 10

    Incorrect syntax near '@declaration'.

    Msg 178, Level 15, State 1, Procedure count_rows, Line 14

    A RETURN statement with a return value cannot be used in this context.

  • mayankminawat (8/9/2014)


    Hello everyone-

    I'm trying to create a simple function that will do a count on a table. I want to pass the table name in form of a parameter to the variable and this function will return the count as an int. Please see my function below and help me understand why this is not working.

    Firstly the limitations of User Defined Functions prohibit the use of dynamic sql, so this approach has no chance of success.

    😎

    Here are two alternative ways, the first is a scalar function thatone uses a predefined list of tables.

    The second one is an inlinable table value function which queries the sys.partitions system view.

    CREATE FUNCTION dbo.FN_COUNT_ROWS

    (

    @TABLE_NAME NVARCHAR(128)

    )

    RETURNS INT

    AS

    BEGIN

    DECLARE @RVAL INT = 0;

    SELECT @RVAL =

    CASE

    WHEN @TABLE_NAME = N'dbo.TABLE_1' THEN (SELECT COUNT(*) FROM dbo.TABLE_1)

    WHEN @TABLE_NAME = N'dbo.TABLE_2' THEN (SELECT COUNT(*) FROM dbo.TABLE_2)

    WHEN @TABLE_NAME = N'dbo.TABLE_3' THEN (SELECT COUNT(*) FROM dbo.TABLE_3)

    ELSE 0

    END

    RETURN @RVAL

    END

    Usage

    DECLARE @TABLE_NAME NVARCHAR(128) = N'dbo_TABLE_2';

    SELECT dbo.FN_COUNT_ROWS(@TABLE_NAME)

    Method #2

    CREATE FUNCTION dbo.FN_COUNT_ROWS2

    (

    @TABLE_NAME NVARCHAR(128)

    )

    RETURNS TABLE

    AS

    RETURN

    SELECT TOP 1 rows AS ROW_COUNT FROM sys.partitions

    WHERE object_id = OBJECT_ID(@TABLE_NAME)

    Usage

    SELECT ROW_COUNT FROM dbo.FN_COUNT_ROWS2(@TABLE_NAME) AS X

  • I'd like to change Eirikurs 2nd method just slightly to cover partitioned tables, too:

    CREATE FUNCTION dbo.FN_COUNT_ROWS2

    (

    @TABLE_NAME NVARCHAR(128)

    )

    RETURNS TABLE

    AS

    RETURN

    SELECT SUM(rows) AS ROW_COUNT FROM sys.partitions

    WHERE object_id = OBJECT_ID(@TABLE_NAME)

    Also, keep in mind that this result is just an estimate and does not have to match the exact number of rows.

    But if you're just looking for a "rough figure" then this is my preferred method -especially for large tables- since it's much faster than a COUNT(*).



    Lutz
    A pessimist is an optimist with experience.

    How to get fast answers to your question[/url]
    How to post performance related questions[/url]
    Links for Tally Table [/url] , Cross Tabs [/url] and Dynamic Cross Tabs [/url], Delimited Split Function[/url]

  • LutzM (8/10/2014)


    I'd like to change Eirikurs 2nd method just slightly to cover partitioned tables, too:

    CREATE FUNCTION dbo.FN_COUNT_ROWS2

    (

    @TABLE_NAME NVARCHAR(128)

    )

    RETURNS TABLE

    AS

    RETURN

    SELECT SUM(rows) AS ROW_COUNT FROM sys.partitions

    WHERE object_id = OBJECT_ID(@TABLE_NAME)

    Also, keep in mind that this result is just an estimate and does not have to match the exact number of rows.

    But if you're just looking for a "rough figure" then this is my preferred method -especially for large tables- since it's much faster than a COUNT(*).

    Thank you Lutz for correcting my incomplete answer;-)

    On the "rough figure", if I recall correctly the count should be accurate for SQL Server 2012/2014.

    😎

  • Quote from BOL(SS2K14):

    rows (bigint): Indicates the approximate number of rows in this partition.



    Lutz
    A pessimist is an optimist with experience.

    How to get fast answers to your question[/url]
    How to post performance related questions[/url]
    Links for Tally Table [/url] , Cross Tabs [/url] and Dynamic Cross Tabs [/url], Delimited Split Function[/url]

  • Eirikur Eiriksson (8/10/2014)


    LutzM (8/10/2014)


    I'd like to change Eirikurs 2nd method just slightly to cover partitioned tables, too:

    CREATE FUNCTION dbo.FN_COUNT_ROWS2

    (

    @TABLE_NAME NVARCHAR(128)

    )

    RETURNS TABLE

    AS

    RETURN

    SELECT SUM(rows) AS ROW_COUNT FROM sys.partitions

    WHERE object_id = OBJECT_ID(@TABLE_NAME)

    Also, keep in mind that this result is just an estimate and does not have to match the exact number of rows.

    But if you're just looking for a "rough figure" then this is my preferred method -especially for large tables- since it's much faster than a COUNT(*).

    Thank you Lutz for correcting my incomplete answer;-)

    On the "rough figure", if I recall correctly the count should be accurate for SQL Server 2012/2014.

    😎

    And I would like to modify it just a little more:

    CREATE FUNCTION dbo.FN_COUNT_ROWS2

    (

    @TABLE_NAME NVARCHAR(128)

    )

    RETURNS TABLE

    AS

    RETURN

    SELECT

    SUM(rows) AS ROW_COUNT

    FROM

    sys.partitions

    WHERE

    object_id = OBJECT_ID(@TABLE_NAME) and index_id in (0,1);

  • Thank you for all the assistance. I am able to get the function to run but when I do the following in a T-SQL block, I am getting an error:

    DECLARE @email varchar(500)

    ,@intFlag INT

    ,@INTFLAGMAX int

    ,@TABLE_NAME VARCHAR(100)

    SET @intFlag =1

    SET @TABLE_NAME='dbO.TD_EmployeeProfile_FinalV2'

    set @email = ('XYG@gmail.com')

    set @INTFLAGMAX=SELECT ROW_COUNT FROM dbo.FN_COUNT_ROWS2 (@TABLE_NAME)AS X

    WHILE @intFlag <= @INTFLAGMAX

    BEGIN

    PRINT @INTFLAGMAX

    SET @intFlag = @intFlag + 1

    END

    GO

    -------------------------

    Msg 102, Level 15, State 1, Line 14

    Incorrect syntax near '@INTFLAGMAX'.

    Msg 102, Level 15, State 1, Line 23

    Incorrect syntax near 'END'.

  • mayankminawat (8/10/2014)


    Thank you for all the assistance. I am able to get the function to run but when I do the following in a T-SQL block, I am getting an error:

    DECLARE @email varchar(500)

    ,@intFlag INT

    ,@INTFLAGMAX int

    ,@TABLE_NAME VARCHAR(100)

    SET @intFlag =1

    SET @TABLE_NAME='dbO.TD_EmployeeProfile_FinalV2'

    set @email = ('XYG@gmail.com')

    set @INTFLAGMAX=SELECT ROW_COUNT FROM dbo.FN_COUNT_ROWS2 (@TABLE_NAME)AS X

    WHILE @intFlag <= @INTFLAGMAX

    BEGIN

    PRINT @INTFLAGMAX

    SET @intFlag = @intFlag + 1

    END

    GO

    -------------------------

    Msg 102, Level 15, State 1, Line 14

    Incorrect syntax near '@INTFLAGMAX'.

    Msg 102, Level 15, State 1, Line 23

    Incorrect syntax near 'END'.

    Try this:

    DECLARE @email varchar(500)

    ,@intFlag INT

    ,@INTFLAGMAX int

    ,@TABLE_NAME VARCHAR(100)

    SET @intFlag =1

    SET @TABLE_NAME='dbO.TD_EmployeeProfile_FinalV2'

    set @email = ('XYG@gmail.com')

    SELECT @INTFLAGMAX = ROW_COUNT FROM dbo.FN_COUNT_ROWS2 (@TABLE_NAME)AS X

    WHILE @intFlag <= @INTFLAGMAX

    BEGIN

    PRINT @INTFLAGMAX

    SET @intFlag = @intFlag + 1

    END

    GO

  • LutzM (8/10/2014)


    Quote from BOL(SS2K14):

    rows (bigint): Indicates the approximate number of rows in this partition.

    The value from sys.partitions is accurate, with the exception of a bug in SQL.

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • GilaMonster (8/10/2014)


    LutzM (8/10/2014)


    Quote from BOL(SS2K14):

    rows (bigint): Indicates the approximate number of rows in this partition.

    The value from sys.partitions is accurate, with the exception of a bug in SQL.

    So, BOL is wrong then when showing "approximate number"?



    Lutz
    A pessimist is an optimist with experience.

    How to get fast answers to your question[/url]
    How to post performance related questions[/url]
    Links for Tally Table [/url] , Cross Tabs [/url] and Dynamic Cross Tabs [/url], Delimited Split Function[/url]

  • LutzM (8/10/2014)


    GilaMonster (8/10/2014)


    LutzM (8/10/2014)


    Quote from BOL(SS2K14):

    rows (bigint): Indicates the approximate number of rows in this partition.

    The value from sys.partitions is accurate, with the exception of a bug in SQL.

    So, BOL is wrong then when showing "approximate number"?

    Less 'wrong' and more 'hasn't been updated since SQL 2000 other than changing sysindexes to sys.partitions'

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • Are the row count values in sys.partitions accurate in general or is there a SQL Server version where the data started being "reliable" rather than "approximate"?



    Lutz
    A pessimist is an optimist with experience.

    How to get fast answers to your question[/url]
    How to post performance related questions[/url]
    Links for Tally Table [/url] , Cross Tabs [/url] and Dynamic Cross Tabs [/url], Delimited Split Function[/url]

  • 2005. The row counts in sys.partitions are supposed to be transactionally correct. If they are not, it is a bug and should be reported.

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass

Viewing 13 posts - 1 through 12 (of 12 total)

You must be logged in to reply to this topic. Login to reply