Geekette
Geekette

Reputation: 83

How do you define a scalar-valued UDF?

I'm reading Microsoft's 70-433 SQL Training Kit, and I've come up against an example where they define the following as a "scalar UDF":

CREATE FUNCTION dbo.fnGetCustomerAccountNumber(@CustomerID INT)
RETURNS VARCHAR(10)
AS
BEGIN
    RETURN ISNULL(
        (
        SELECT
            AccountNumber
        FROM Sales.Customer
        WHERE CustomerID = @CustomerID
    ), 'NOT FOUND');
END
GO

I understand that a scalar UDF (as oppposed to a table-valued one) is one that returns a single value, but it seems to me that the above function will only return a single value if there is only one row returned by the SELECT statement - which will depend on the contents of the table. But I'm happy to assume that there will be only one row returned (what would happen if there wasn't?). But...

They then give an alternative version, which instead of calling the above UDF, does the following:

SELECT 
    soh.SalesOrderID
    , soh.OrderDate
    , ISNULL(
        (
        SELECT
            AccountNumber
        FROM Sales.Customer
        WHERE CustomerID = soh.CustomerID
    ), 'NOT FOUND')
FROM Sales.SalesOrderHeader AS soh;

They contrast this second example by saying "The use of inline table-valued UDFs does not incur the same performance penalty as the use of scalar UDFs because..."

So, this second example, even though the code is identical to the first, is a table-valued UDF rather than a scalar one? Is this an error in the text, or am I misunderstanding the distinction between a scalar UDF and a table-valued one?

Upvotes: 1

Views: 1629

Answers (1)

Hogan
Hogan

Reputation: 70538

There is a difference. Look at the where clause in the first

   WHERE CustomerID = @CustomerID

Is matching CustomerID against a single integer value (which is a parameter.)

In the 2nd where clause

   WHERE CustomerID = soh.CustomerID

Is matching against every value of CustomerID in the Sales.SalesOrderHeader table.

Upvotes: 1

Related Questions