0

I have 2 function

frist find name of employee when Employee.id = id

CREATE FUNCTION FindEmployeeName
 (
    @id bit 
 )
RETURNS varchar(32)
AS
BEGIN
    declare @name varchar(32) 
    set @name=( SELECT Employee.Id FROM Employee WHERE Id=@id)
RETURN  @name
END 

second find name of Doctor when Doctor.id = id :

CREATE FUNCTION FindDoctorName
 (
    @id bit 
 )
RETURNS varchar(32)
AS
BEGIN
    declare @name varchar(32) 
    set @name=( SELECT Doctor.Id FROM Doctor WHERE Id=@id)
RETURN  @name
END 

Now, Can I have dynamic function ?

pass table and id to function and return name?

CREATE FUNCTION FindEmployeeName
 (
    @id bit ,
    @tbl varcahr(32)
 )
RETURNS varchar(32)
AS
BEGIN
    declare @name varchar(32) 
    set @name=( SELECT @tbl.Id FROM @tbl WHERE Id=@id)
RETURN  @name
END 

Is there a better way?

Edited my schema is: enter image description here

5
  • 2
    You can but the performance is going to suck and would be a total kludge. The problem is you need to execute dynamic sql and in a function that makes it non-deterministic. There are some work arounds but honestly this type of process that can do everything from one piece of code is not a good approach. You wouldn't create a .net method that can find data from any object. Commented Aug 1, 2014 at 20:30
  • 1
    If anything I would create a "driver" type of procedure that could receive a parameter that lets you know which of your other procedures to execute. That is a LOT cleaner and the performance will not suffer. Commented Aug 1, 2014 at 20:31
  • Perhaps this issue is telling you that a Person table, super-type of both Doctor and Patient storing the columns common to both, is required in your schema. Commented Aug 1, 2014 at 20:46
  • @SeanLange How to write clean code? how to create "driver" procedure? Commented Aug 1, 2014 at 20:51
  • @PieterGeerkens schema Added Commented Aug 1, 2014 at 20:53

3 Answers 3

3

No you cannot pass a table name as variable to a User defined function as you will need dynamic sql to build the query and execute and this is something you cannot do inside a function, you will need to use a stored procedure for this .. something like this......

CREATE PROCEDURE FindEmployeeName
    @id INT ,   --<-- I dont think you need BIT here, BIT can only 1 or 0
    @tbl sysname,
    @Name varchar(32) OUTPUT
AS
BEGIN
 SET NOCOUNT ON;

   DECLARE @SQL NVARCHAR(MAX);

  SET @SQL =  N' SELECT @Name = Name FROM ' + QUOTENAME(@tbl)
            + N' WHERE Id = @id '
 EXECUTE sp_executesql @SQL 
                      ,N'@id INT , @Name varchar(32) OUTPUT'
                      ,@Id
                      ,@Name OUTPUT
END 
Sign up to request clarification or add additional context in comments.

Comments

1

I would do this without dynamic sql if at all possible. Here is one way to do that. Basically you would end up with three procedures but the performance is well worth it. Take a look at this article which explores the performance benefits of this type of approach. http://sqlinthewild.co.za/index.php/2009/09/15/multiple-execution-paths/

create procedure GetDoctorData
(
    @Id int
) as
    select Doctor.Id FROM Doctor WHERE Id=@id

go

create procedure GetEmployeeData
(
    @Id int
) as
    select Employee.Id FROM Employee WHERE Id=@id

go

create procedure GetPersonData
(
    @PersonType varchar(10)
    , @Id int
) as

    if @PersonType = 'Doctor'
        exec GetDoctorData @Id      

    if @PersonType = 'Employee'
        exec GetEmployeeData @Id

go

6 Comments

Excellent point about the performance benefit with the three procs. This avoids the parameter sniffing issue. Also, an excellent article by Gail Shaw.
Another thought: could the OP take your strategy and use three UDF's instead of three SP's?
Dynamic sql when called using particularized sp_executesql is cached in the execution plan so you do not have to create additional objects such as SP's in fear of performance
@GouriShankarAechoor it is true that dynamic sql is cached. You should read the article I posted. Gail goes into great detail about how this caching can adversely affect performance in situations like this. The basic gist is that with different parameters you might need a different execution plan.
@SeanLange, scenario based yes but I do not see the number of tables being huge in this scenario( 3 variants ) so I would imagine it should be fine. However, please can you add the link to article so I can gain some information on it. Appreciate it. Thanks.
|
0
DECLARE @id INT;                            
DECLARE @tblName VARCHAR(100);
SET @id = 1;
SET @tblName = 'Employee'

DECLARE @sqlString VARCHAR(500);
SET @sqlString = 'SELECT *'
                    + ' FROM ' +@tblName
                    + ' WHERE Id = ' + CAST(@id AS VARCHAR(100));
--PRINT(@sqlString);
EXEC (@sqlString);

i have only demonstrated it to show how we can turn string to sql query. But take the suggestion as 'Sean Lange' pointed.

2 Comments

This method is dangerous, vulnerable to sql injection attack.
did n't i mention "i have only demonstrated it to show how we can turn string to sql query"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.