2016-05-25 10 views
2

私は確かに答えはいいですが、私は二重チェックしたいです。方法がある場合、実際にコードを記述する必要はありませんが、メソッドの提案が役立つ可能性があります。私はサブクエリなどで1つの大きな選択を試みましたが、正しいレコードを選択する方法を理解できません。このスカラー関数からインラインテーブル値関数を作成することは可能ですか?

逆の関係を得るために、テーブル自体に戻ってきてください。以下のコードは単なるテストサンプルです。

これはテストのために、いくつかのレコードを持つテーブルです

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

を、このモデル我々は継続的に列を追加1行の表によるスカラー一連の計算...

は、これはパフォーマンスで、クエリになる可能性があります問題。おそらくループ結合を強制するでしょう。

+0

天才、ありがとう!これまで、これを使って関数をインラインバージョンに書き直すことができました。私のテスト例は完全に動作します。私はいくつかのより大きなデータセットでそれを実行し、それは動作し、パフォーマンスの改善と思われた。私はそれをさらに大きなデータセットで実行しました。私は以下のエラーを受け取りました。私は関数の構造を見てそれがどのように可能であるか分かりません。任意のアイデア?エラー:サブクエリは1つ以上の値を返しました。サブクエリが=、!=、<, <= , >、> =、またはサブクエリが式として使用されているときは、これは許可されません。 –

+0

私は問題がどこにあるのかわかります。あなたの例では、{computefallback}にサブクエリがあります。どこかで、結果が2行になるという基準を満たしています。私はそれらのシナリオでは、古い関数は "更新"のように動作し、ちょうど最初の値を選ぶと思います。おそらく、既存のロジックがやっているような要素を選択するためにMAX()を追加することができます。 –

+0

古いコードにバグがありました。非確定的な値が選択されました...右、あなたはMAXまたはTOP 1 ORDER BYを使用することができます.... – usr

関連する問題