是否可以使用此标量函数创建内联表值函数?

时间:2016-05-25 20:35:15

标签: sql sql-server function database-performance

我很确定答案是否定的,但我想仔细检查。如果有办法,你实际上不必对其进行编码,对方法的建议可能有所帮助。我已经尝试了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 个答案:

答案 0 :(得分: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
...

本质上,它通过一行表格对一系列标量计算进行建模,我们不断向...添加列...

这可能会导致查询出现性能问题。它可能会强制循环连接。