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
答案 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