Làm thế nào để tham gia một bảng với một chức năng có giá trị bảng?


53

Tôi có một chức năng do người dùng định nghĩa:

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

Bây giờ tôi muốn tham gia cái này trên một cái bàn khác, như vậy:

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

Nói cách khác, đối với tất cả các Foobản ghi SomeCriterionlà 1, tôi muốn xem Foo IDDesc, cùng với các giá trị của Field1Field2được trả về từ ut_FooFuncđầu vào của Foo.ID.

Cú pháp để làm điều này là gì?

Câu trả lời:


84

Bạn CROSS APPLYkhông cần tham gia.

Định nghĩa của các biểu thức bảng liên quan đến các phép nối phải ổn định. Tức là Chúng không thể tương quan sao cho biểu thức bảng có nghĩa là một cái gì đó khác nhau phụ thuộc vào giá trị của một hàng trong bảng khác.

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

0

Tôi biết chủ đề đã cũ, tôi đã được hỏi cùng một câu hỏi, tôi đã làm một bài kiểm tra, kết quả như sau ...

Các bản ghi trong FacCurrencyRate = 14264 trong khi TestFunction trả về 105 nếu được thực thi độc lập.

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

Thời gian thực hiện là ...

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

Nếu tôi sử dụng câu trả lời được đề xuất như sau ...

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

Thời gian thực hiện và số lượng kết quả là ...

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

Những gì tôi thấy ở đây là truy vấn bên trong đưa ra tập kết quả chính xác hơn và thời gian thực hiện hiệu quả hơn nhiều. Hãy sửa tôi với cách tiếp cận tốt hơn để hoàn thành tương tự!


1
Áp dụng chéo được áp dụng cho từng hàng ngoài (vì vậy từng hàng), đây là lý do tại sao nó chậm hơn rất nhiều, đặc biệt là trên các bộ dữ liệu lớn hơn. Bằng cách đảo ngược nó (vì bạn chỉ muốn kết quả có trận đấu trong TVF, sau đó bạn giảm đáng kể thời gian ngoại lệ (không có cuộc gọi nào không làm gì) cũng như số lượng hàng bạn nhận được. Nhưng hai câu lệnh của bạn không tương đương trả về nhiều hàng hơn so với hàng đầu tiên. Theo như tính chính xác, điều đó phụ thuộc vào yêu cầu kinh doanh của bạn.
Jonathan Fite

Vâng tôi đồng ý. Tuy nhiên, tôi đã viết mã theo câu hỏi ban đầu, trong đó tôi giả sử rằng có một mối quan hệ một đến nhiều giữa các bảng. Và, thứ hai, tôi đã được hỏi một câu hỏi trong một cuộc phỏng vấn. Cảm ơn
user3104116
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.