Como ingressar em uma tabela com uma função com valor de tabela?


53

Eu tenho uma função definida pelo usuário:

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

Agora eu quero juntar isso em outra tabela, assim:

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

Em outras palavras, para todos os Fooregistros onde SomeCriterioné 1, quero ver o Foo IDe Desc, juntamente com os valores de Field1e Field2que são retornados ut_FooFuncpara uma entrada de Foo.ID.

Qual é a sintaxe para fazer isso?

Respostas:


84

Você CROSS APPLYnão precisa participar.

A definição de expressões de tabela envolvidas em junções deve ser estável. Ou seja, eles não podem ser correlacionados de modo que a expressão da tabela signifique algo diferente, dependendo do valor de uma linha em outra tabela.

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

0

Eu sei que o tópico é antigo, me fizeram a mesma pergunta, fiz um teste, o resultado da seguinte forma ...

Registros em FacCurrencyRate = 14264 enquanto TestFunction retorna 105 se executado independentemente.

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

O tempo de execução é ...

    (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 eu usar a resposta sugerida da seguinte maneira ...

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

O tempo de execução e a contagem de resultados são ...

(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.

O que vejo aqui é que a consulta interna traz um conjunto mais correto de resultados e o tempo de execução é muito mais eficiente. Corrija-me com uma abordagem melhor para realizar o mesmo!


11
A aplicação cruzada é aplicada a cada linha externa (linha por linha); é por isso que é muito mais lenta, especialmente em conjuntos de dados maiores. Ao revertê-lo (porque você deseja apenas resultados que correspondam ao TVF, reduz bastante o tempo de execução (sem chamadas que não fazem nada), bem como quantas linhas são retornadas. Mas suas duas instruções não são equivalentes à segunda retorna muito mais linhas que a primeira.Tanto quanto a correção, isso depende dos requisitos da sua empresa
Jonathan Fite 18/04

Sim eu concordo. No entanto, escrevi o código à luz da pergunta inicial, na qual assumi que existe uma relação entre muitas tabelas. E, em segundo lugar, me fizeram uma pergunta em uma entrevista. Graças
user3104116
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.