2016-05-25 80 views
2

我很確定答案是否定的,但我想仔細檢查。如果有辦法,你實際上不需要編寫代碼,對方法的建議可能會有所幫助。我已經嘗試了一個大的選擇與子查詢等,但我不知道如何讓它選擇正確的記錄。是否可以使用此標量函數創建內聯表值函數?

該表必須自行聯結以獲得反向關係。下面的代碼只是一個測試樣例。

謝謝

create function [dbo].[fnUOMFactor_Inline] (
     @ItemID  nvarchar(20) 
,  @FromUnit nvarchar(10) 
,  @ToUnit  nvarchar(10) 
    ) 

returns numeric(28,12) 
as 
begin 

declare @Factor  numeric(28,12) 


if  @FromUnit = @ToUnit 
set  @Factor = 1 

--  Simple 1-step 
if  @Factor is null 
select @Factor = factor 
from dbo.UnitConvertTest 
WHere itemid = @ItemID 
and  fromunit = @FromUnit 
and  tounit = @ToUnit 


--  Inverted 1-step 
if  @Factor is null 
select @Factor = 1/factor 
from dbo.UnitConvertTest 
Where itemid = @ItemID 
and  fromunit = @ToUnit 
and  tounit = @FromUnit 


if  @Factor is null 
select @Factor = uc1.factor * uc2.factor 
from dbo.UnitConvertTest uc1 
join dbo.UnitConvertTest uc2 on uc1.itemid = uc2.itemid 
          and uc1.tounit = uc2.fromunit 

where uc1.itemid = @ItemID 
and  uc1.fromunit = @FromUnit 
and  uc2.tounit = @ToUnit 
and  uc1.factor <> 0 
and  uc2.factor <> 0 

--  Inverted 2-step 
if  @Factor is null 
select @Factor = 1/(uc1.factor * uc2.factor) 
from dbo.UnitConvertTest uc1 
join dbo.UnitConvertTest uc2  on uc1.itemid = uc2.itemid 
           and uc1.tounit = uc2.fromunit 
Where uc1.itemid = @ItemID 
and  uc1.fromunit = @ToUnit 
and  uc2.tounit = @FromUnit 

--  Complex 2-step (same fromunit) 
if  @Factor is null 
select @Factor = uc1.factor/uc2.factor 
from dbo.UnitConvertTest uc1 
join dbo.UnitConvertTest uc2 on uc1.itemid = uc2.itemid 
          and uc1.fromunit = uc2.fromunit 
Where uc1.itemid = @ItemID 
and  uc1.tounit = @ToUnit 
and  uc2.tounit = @FromUnit 


--  Complex 2-step (same tounit) 
if  @Factor is null 
select @Factor = uc1.factor/uc2.factor 
from dbo.UnitConvertTest uc1 
join dbo.UnitConvertTest uc2 on uc1.itemid = uc2.itemid 
          and uc1.tounit = uc2.tounit 
Where uc1.itemid = @ItemID 
and  uc1.fromunit = @FromUnit 
and  uc2.fromunit = @ToUnit 

--  Default 
if  @Factor is null 
set  @Factor = 1 

return @Factor 
end 

這是一個用於測試的一些記錄表格。

CREATE TABLE [dbo].[UnitConvertTest](
[FROMUNIT] [nvarchar](10) NOT NULL, 
[TOUNIT] [nvarchar](10) NOT NULL, 
[FACTOR] [numeric](28,12) NOT NULL, 
[ITEMID] [nvarchar](20) NOT NULL, 
) ON [PRIMARY] 

insert into dbo.UnitConvertTest (FROMUNIT, TOUNIT, FACTOR, ITEMID) 

Values ('CT','PT','40.00','TEST') 
,  ('RM','CT','10.00','TEST') 
,  ('RM','PT','400.00','TEST') 


Select [dbo].[fnUOMFactor_Inline] ('Test','PT','RM') 

回答

1

任何無環標量函數都可以通過機械轉換轉化爲內聯TVP。不過,轉換可能會導致一個大的查詢。

您的代碼似乎是一個後備計算鏈。你可以寫這樣的:

select FinalResult = coalesce(x.factor, f1.fallback, f2.fallback, f3.fallback, ...) 
from (values (convert(decimal(28, 12, null))) x(factor) 
cross apply (select fallback = {computeFallback1}) f1 
cross apply (select fallback = {computeFallback2}) f2 
cross apply (select fallback = {computeFallback3}) f3 
... 

從本質上講,這種模式通過一個行的表,我們不斷地將列添加到一系列標計算的......

這可能會導致其性能查詢的問題。它可能會強制循環連接。

+0

天才,謝謝!到目前爲止,我能夠使用這個函數將函數重新編寫爲內聯版本,並且我的測試示例完美無缺。我通過一些更大的數據集來運行它,它似乎工作並且是一個性能改進。然後我通過一個更大的數據集來運行它,並且我得到了下面的錯誤。我不確定基於查看函數結構的可能性。任何想法?錯誤:子查詢返回多個值。當子查詢遵循=,!=,<, <= , >,> =或當子查詢用作表達式時,這是不允許的。 –

+0

我想我會看到問題的可能性。在你的例子中,我有{computefallback}中的子查詢。某處,我符合標準導致2行。我猜舊函數在這些場景中就像一個「更新」,只是選擇第一個值。也許我可以添加一個MAX()來選擇一個像現有邏輯正在做的因素。 –

+0

舊的代碼有一個bug。一個非確定性值被選中......對,你可以使用MAX或TOP 1 ORDER BY .... – usr

相關問題