Як з'єднати таблицю з функцією оцінювання таблиці?


53

У мене є визначена користувачем функція:

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

Тепер я хочу приєднатися до цього на іншій таблиці, як-от так:

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

Іншими словами, для всіх Fooзаписів, де SomeCriterionє 1, я хочу бачити значення Foo IDта Descпоряд з значеннями Field1та Field2, які повертаються ut_FooFuncдля введення Foo.ID.

Який синтаксис для цього робити?

Відповіді:


84

Вам CROSS APPLYне потрібно приєднуватися.

Визначення табличних виразів, що беруть участь у з'єднанні, повинно бути стабільним. Тобто вони не можуть бути пов'язані таким чином, що вираження таблиці означає щось інше, залежне від значення рядка в іншій таблиці.

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

0

Я знаю, що нитка стара, мені задали те саме питання, я зробив тест, результат наступний ...

Записи в FacCurrencyRate = 14264, тоді як TestFunction повертає 105, якщо виконано самостійно.

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

Час виконання ...

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

Якщо я використовую запропоновану відповідь так:

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

Час виконання та кількість результатів ...

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

Я бачу тут те, що внутрішній запит виявляє більш правильний набір результатів, а час виконання набагато ефективніше. Виправте мене кращим підходом до того ж!


1
Перехресне нанесення застосовується до кожного зовнішнього ряду (так що рядок за рядком), тому це набагато повільніше, особливо на великих наборах даних. Повернувши його назад (оскільки ви хочете лише отримати результати, які мають збіг у TVF, ви значно скорочуєте час виконання (без викликів, які нічого не роблять)), а також кількість рядків, які ви повертаєте. повертає набагато більше рядків, ніж перший. Що стосується коректності, це залежить від ваших вимог бізнесу.
Джонатан Фейт,

Так, я згоден. Однак я написав код у світлі початкового запитання, де я припускав, що між таблицями існує взаємозв'язок між багатьма. І, по-друге, мені було задано питання в інтерв'ю. Дякую
користувач3104116
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.