Select语句中的SQL表值函数

时间:2013-10-11 14:31:30

标签: sql sql-server tsql

SQL不是我最好的事情,但我一直在尝试优化这个存储过程。它有多个标量值函数,我试图改变为表值函数,因为我在很多地方读到它是一种更有效的方法。现在我制作了它们,但不确定如何实现,或者我可能只是没有正确创建它们。

这是我正在打电话的功能。

Alter FUNCTION [IsNotSenateActivityTableValue]
(
    @ActivityCode int,
    @BillId int,
    @TextToDisplay varchar(max)
)
returns @T table(result varchar(max))
as
begin
DECLARE @result varchar(max);
    declare @countcodes int;


declare @ishousebill int;

select @ishousebill = count(billid)
from BillMaster
where BillID = @BillID and Chamber = 'H'

If (@ishousebill = 0)
begin


SELECT @countcodes = count([ActivityCode])
      FROM [HouseCoreData].[dbo].[ActivityCode]
      where ActivityDescription not like '%(H)%' and ActivityType = 'S'
      and [ActivityCode] = @ActivityCode

if (@countcodes = 0)
begin
    set @result = 'test'
   end
  else
     begin
        set @result = 'test2'
    end
end
else
begin
    set @result = @TextToDisplay
end
RETURN 

END

这就是我试图像这样打电话给他们的方式。我希望能够将它们放在顶部,但实际上任何有用的东西都会很好。

SELECT distinct       
      ActionDates.result as ActionDate
      ,ActivityDescriptions.result as ActivityDescription        
  FROM BillWebReporting.vwBillDetailWithSubjectIndex as vw
  left outer join [BillWebReporting].[HasHouseSummary] as HasSummary on vw.BillID = HasSummary.BillID
  outer APPLY dbo.IsNotSenateActivityDateTableValue(ActivityCode,vw.BillID,[ActionDate]) ActionDates    
  OUTER APPLY dbo.IsNotSenateActivityTableValue(ActivityCode,vw.BillID,[ActivityDescription]) as ActivityDescriptions

3 个答案:

答案 0 :(得分:3)

获取计数只是为了查看是否存在至少一行是非常昂贵。您应该使用EXISTS代替,这可能会短路而不会实现整个计数。

这是一种使用内联表值函数而不是多语句表值函数的更有效方法。

ALTER FUNCTION dbo.[IsNotSenateActivityTableValue] -- always use schema prefix!
(
    @ActivityCode int,
    @BillId int,
    @TextToDisplay varchar(max)
)
RETURNS TABLE
AS
  RETURN (SELECT result = CASE WHEN EXISTS 
    (SELECT 1 FROM dbo.BillMaster 
     WHERE BillID = @BillID AND Chamber = 'H'
  ) THEN @TextToDisplay ELSE CASE WHEN EXISTS 
    (SELECT 1 FROM [HouseCoreData].[dbo].[ActivityCode]
      where ActivityDescription not like '%(H)%' 
      and ActivityType = 'S'
      and [ActivityCode] = @ActivityCode
  ) THEN 'test2' ELSE 'test' END
  END);
GO

当然它也可能只是一个标量UDF ......

ALTER FUNCTION dbo.[IsNotSenateActivityScalar] -- always use schema prefix!
(
    @ActivityCode int,
    @BillId int,
    @TextToDisplay varchar(max)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
  DECLARE @result VARCHAR(MAX);

  SELECT @result = CASE WHEN EXISTS 
    (SELECT 1 FROM dbo.BillMaster 
     WHERE BillID = @BillID AND Chamber = 'H'
  ) THEN @TextToDisplay ELSE CASE WHEN EXISTS 
    (SELECT 1 FROM [HouseCoreData].[dbo].[ActivityCode]
      where ActivityDescription not like '%(H)%' 
      and ActivityType = 'S'
      and [ActivityCode] = @ActivityCode
  ) THEN 'test2' ELSE 'test' END
  END;

  RETURN (@result);
END
GO

答案 1 :(得分:0)

表值函数返回一个表,其中,与任何其他表一样,必须插入行。

不要执行set @result = .....,而是执行:

INSERT INTO @T (result) VALUES ( ..... )

编辑:作为旁注,我真的不明白这个函数是表值的原因。您基本上返回一个值。

答案 2 :(得分:0)

首先,UDF通常非常不具备性能。我不确定MySQL,但在Sql Server中,每次重新编译UDF(FOR EACH ROW OF OUTPUT)都会执行它,除了所谓的 内联 UDF,它只有一个select语句,它被折叠到它包含在外部查询的SQL中......因此只编译一次。

MySQL确实有inline table-valued functions,而是在SQL Server中使用它...语法为:

CREATE FUNCTION IsNotSenateActivityTableValue
(
@ActivityCode int,
@BillId int,
@TextToDisplay varchar(max)
)
RETURNS TABLE 
AS
RETURN 
(
Select case 
   When y.bilCnt + z.actCnt = 0 Then 'test'
   when y.bilCnt = 0 then 'test2'
   else @TextToDisplay end result
From (Select Count(billId) bilCnt
      From BillMaster
      Where BillID = @BillID 
         And Chamber = 'H') y
    Full Join 
     (Select count([ActivityCode]) actCnt
      From [HouseCoreData].[dbo].[ActivityCode]
      Where ActivityDescription not like '%(H)%' 
         And ActivityType = 'S'
         And [ActivityCode] = @ActivityCode) z

)
GO