Molto probabilmente il motivo principale è che le funzioni con valori di tabella restituiscono un set di risultati, proprio come le tabelle e le viste. Questo significa che possono essere utilizzati nella FROM
clausola (tra cui JOIN
s e APPLY
s, ecc) di SELECT
, UPDATE
e DELETE
le query. Tuttavia, non è possibile utilizzare un UDF scalare in nessuno di questi contesti.
Secondariamente, puoi anche EXECUTE
un UDF scalare. Questa sintassi è abbastanza utile quando si hanno valori predefiniti specificati per i parametri di input. Prendi il seguente UDF, per esempio:
CREATE FUNCTION dbo.OptionalParameterTest (@Param1 INT = 1, @Param2 INT = 2)
RETURNS INT
AS
BEGIN
RETURN @Param1 + @Param2;
END;
Se vuoi considerare uno qualsiasi dei parametri di input come "opzionale", devi comunque passare la DEFAULT
parola chiave quando la chiami come una funzione poiché la firma è fissa:
DECLARE @Bob1 INT;
SET @Bob1 = dbo.OptionalParameterTest(100, DEFAULT);
SELECT @Bob1;
-- Returns: 102
D'altra parte, se si EXECUTE
dispone della funzione, è possibile considerare qualsiasi parametro con un valore predefinito come veramente facoltativo, proprio come è possibile con Stored Procedures. È possibile passare i primi n parametri senza specificare i nomi dei parametri:
DECLARE @Bob2 INT;
EXEC @Bob2 = dbo.OptionalParameterTest 50;
SELECT @Bob2;
-- Returns: 52
Puoi anche saltare il primo parametro specificando nuovamente i nomi dei parametri, proprio come con Stored Procedures:
DECLARE @Bob3 INT;
EXEC @Bob3 = dbo.OptionalParameterTest @Param2 = 50;
SELECT @Bob3;
-- Returns: 51
AGGIORNARE
Perché potresti voler usare la EXEC
sintassi per chiamare un UDF scalare proprio come una Stored Procedure? Occasionalmente ci sono UDF che sono fantastici da avere come UDF poiché possono essere aggiunti a una query e operare sull'insieme di righe restituite, mentre se il codice fosse in una Stored Procedure allora dovrebbe essere posizionato in un cursore per iterare su una serie di righe. Ma poi ci sono volte che vuoi chiamare quella funzione su un singolo valore, possibilmente da un altro UDF. La chiamata di un UDF per un singolo valore può essere eseguita come:
SELECT dbo.UDF('some value');
nel qual caso si ottiene un valore di ritorno in un set di risultati (un set di risultati non funzionerà). O potrebbe essere fatto come segue:
DECLARE @Dummy INT;
SET @Dummy = dbo.UDF('some value');
nel qual caso è necessario dichiarare la @Dummy
variabile;
TUTTAVIA, con la EXEC
sintassi, puoi evitare entrambi questi fastidi:
EXEC dbo.UDF 'some value';
Inoltre, gli UDF scalari hanno i loro piani di esecuzione memorizzati nella cache. Ciò significa che è possibile imbattersi in problemi di sniffing dei parametri se nell'UDF sono presenti query con piani di esecuzione. Per gli scenari in cui è possibile utilizzare la EXEC
sintassi, è anche possibile utilizzare l' WITH RECOMPILE
opzione per ignorare il valore compilato dei piani per tale esecuzione . Per esempio:
IMPOSTARE:
GO
CREATE FUNCTION dbo.TestUDF (@Something INT)
RETURNS INT
AS
BEGIN
DECLARE @Ret INT;
SELECT @Ret = COUNT(*)
FROM sys.indexes si
WHERE si.[index_id] = @Something;
RETURN @Ret;
END;
GO
TEST:
DECLARE @Val INT;
SET @Val = dbo.TestUDF(1);
SELECT @Val;
EXEC @Val = dbo.TestUDF 0 -- uses compiled value of (1)
SELECT @Val;
EXEC @Val = dbo.TestUDF 0 WITH RECOMPILE; -- uses compiled value of (0)
SELECT @Val;
EXEC @Val = dbo.TestUDF 3 -- uses compiled value of (1)
SELECT @Val;