views:

71

answers:

1

I have taken over some code from a previous developer and have come across this SQL statement that calls several SQL functions. As you can see, the function calls in the select statement pass a parameter to the function. How does the SQL statement know what value to replace the variable with? For the below sample, how does the query engine know what to replace nDeptID with when it calls, fn_SelDeptName_DeptID(nDeptID)

nDeptID IS a column in table Note.

SELECT STATEMENT:

SELECT nCustomerID AS [Customer ID], 
 nJobID AS [Job ID], 
 dbo.fn_SelDeptName_DeptID(nDeptID) AS Department, 
 nJobTaskID AS JobTaskID, 
 dbo.fn_SelDeptTaskDesc_OpenTask(nJobID, nJobTaskID) AS Task, 
 nStandardNoteID AS StandardNoteID, 
 dbo.fn_SelNoteTypeDesc(nNoteID) AS [Note Type], 
 dbo.fn_SelGPAStandardNote(nStandardNoteID) AS [Standard Note], 
 nEntryDate AS [Entry Date], 
 nUserName as [Added By], 
 nType AS Type, 
 nNote AS Note FROM Note 
 WHERE nJobID = 844261 
 ORDER BY nJobID, Task, [Entry Date]

======================

Function fn_SelDeptName_DeptID:

ALTER FUNCTION [dbo].[fn_SelDeptName_DeptID] (@iDeptID int)
RETURNS varchar(25)

-- Used by DataCollection for Job Tracking
-- if the Deptartment isnt found return an empty string

BEGIN 
 -- Return the Department name for the given DeptID.
 DECLARE @strDeptName varchar(25)

 IF @iDeptID = 0 
  SET @strDeptName = ''

 ELSE
 BEGIN
  SET @strDeptName = (SELECT dName FROM Department WHERE dDeptID = @iDeptID)
  IF (@strDeptName IS NULL) SET @strDeptName = ''
 END

 RETURN @strDeptName

END

==========================

Thanks in advance.

+5  A: 

Same way it knows how to return a column value when you say SELECT nDeptID FROM Note. Query is compiled, names are bound to metadata, plan is executed, results are obtained.

But I would like to address that using a scalar function instead of a COALESCE on ana outer join is going to suck beyond believe. This is SQL, not a procedural imperative run-of-the-mill-C-derivate language.

Do this instead, for sake of performance:

SELECT nCustomerID AS [Customer ID], 
 nJobID AS [Job ID], 
 COALESCE(d.Name, "") AS Department, 
 ...
 FROM Note 
 LEFT JOIN Departments d ON Note.nDeptID = d.nDeptID
 WHERE nJobID = 844261 
 xORDER BY nJobID, Task, [Entry Date]

I'm pretty sure same applies to every other scalar function in your query.

Remus Rusanu
+1 for not only answering the question but providing useful advice
ig0774
Yes, performance is very poor currently which is why I am rewriting this section of code.
Wait a second, if the query returns 37 records, then each function in the query was called 37 times?!
@geekzlla - Correct. If you put a function in the SELECT clause, it will be executed for each row in the output (depending a bit on the type of function. But using your example...). So, the number of function executions will equal the number of columns that use a function call multiplied by the number of rows in the output.
Thomas
@geekzlla: Most likely will be invoked 37 times. Because the function contains T-SQL procedural statements, the query optimizer cannot guess what is inside the function. But if you put COALESCE and a JOIN, even an outer JOIN, then the optimizer knows exactly what you want and it *may* offer a better plan.
Remus Rusanu
+1; but arguably (subjective) clearer: `ISNULL(d.Name, '') AS ...` . Functionally identical, though.
Marc Gravell
@Marc: I tend to favor COALESCE because is part of the ANSI standards. Not that it really matters at the end of the day.. ;)
Remus Rusanu
@Remus - fair enough (and valid). But *truly* ANSI compliant SQL is so rarely compatible with "optimised for my target platform". Opposite, even. Sadly.
Marc Gravell
@Thomas: No wonder we see such poor performance here.
Thanks to everyone for the information!