Come unire una tabella con una funzione con valori di tabella?


53

Ho una funzione definita dall'utente:

create function ut_FooFunc(@fooID bigint, @anotherParam tinyint)
returns @tbl Table (Field1 int, Field2 varchar(100))
as
begin
  -- blah blah
end

Ora voglio unirmi a questo su un altro tavolo, in questo modo:

select f.ID, f.Desc, u.Field1, u.Field2
from Foo f 
join ut_FooFunc(f.ID, 1) u -- doesn't work
where f.SomeCriterion = 1

In altre parole, per tutti i Foorecord in cui SomeCriterionè 1, voglio vedere il Foo IDe Desc, accanto ai valori di Field1e da Field2cui vengono restituiti ut_FooFuncper un input di Foo.ID.

Qual è la sintassi per farlo?

Risposte:


84

Non è necessario CROSS APPLYpartecipare.

La definizione delle espressioni di tabella coinvolte nei join deve essere stabile. Vale a dire che non possono essere correlati in modo tale che l'espressione della tabella significhi qualcosa di diverso a seconda del valore di una riga in un'altra tabella.

select f.ID, f.Desc, u.Field1, u.Field2
from Foo f 
Cross apply ut_FooFunc(f.ID, 1) u
where f.SomeCriterion = ...

0

So che il thread è vecchio, mi è stata posta la stessa domanda, ho fatto un test, il risultato è il seguente ...

Record in FacCurrencyRate = 14264 mentre TestFunction restituisce 105 se eseguito in modo indipendente.

    SELECT F.*, x.CurrencyKey, x.CurrencyName
    FROM ( 
           SELECT CurrencyKey, CurrencyName FROM dbo.TestFunction()
        ) x
    INNER JOIN [dbo].[FactCurrencyRate] F ON x.CurrencyKey = f.CurrencyKey;

Il tempo di esecuzione è ...

    (14264 rows affected)
    Table 'FactCurrencyRate'. Scan count 1, logical reads 75, physical reads 1, read-ahead reads 73, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'DimCurrency'. Scan count 1, logical reads 2, physical reads 1, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 31 ms,  elapsed time = 749 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

Se utilizzo la risposta suggerita come segue ...

select F.*, x.CurrencyKey, x.CurrencyName from [dbo].[FactCurrencyRate] F
cross apply dbo.TestFunction() x

Il tempo di esecuzione e il conteggio dei risultati è ...

(1497720 rows affected)
Table 'FactCurrencyRate'. Scan count 1, logical reads 75, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 1, logical reads 38110, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'DimCurrency'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 2106 ms,  elapsed time = 43242 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

Quello che vedo qui è che la query interna mette in evidenza una serie più corretta di risultati e i tempi di esecuzione sono molto più efficienti. Correggimi con un approccio migliore per ottenere lo stesso risultato!


1
L'applicazione della croce viene applicata a ciascuna riga esterna (quindi riga per riga), per questo è molto più lenta, specialmente su set di dati più grandi. Invertendolo (perché vuoi solo risultati che abbiano una corrispondenza nel TVF, riduci notevolmente il tempo di visualizzazione (nessuna chiamata che non fa nulla) così come quante righe ti vengono restituite. Ma le tue due dichiarazioni non sono equivalenti alla seconda restituisce molte più righe della prima. Per quanto riguarda la correttezza, ciò dipende dalle esigenze aziendali.
Jonathan Fite,

Si, sono d'accordo. Tuttavia, ho scritto il codice alla luce della domanda iniziale in cui supponevo che vi fosse una o più relazioni tra le tabelle. E, in secondo luogo, mi è stata posta una domanda in un'intervista. Grazie
user3104116
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.