SQL Server用户定义函数来计算年龄段

Jon*_*Way 2 t-sql sql-server

我创建了一个UDF来计算数据库中的年龄段.我使用以下代码

CREATE FUNCTION Agebracket(@Ages INT)
RETURNS VARCHAR
AS
BEGIN
DECLARE @Age_Group varchar 

SET @Age_Group = CASE WHEN @Ages BETWEEN 0 AND 9 THEN  '[0-9]'
                 WHEN @Ages BETWEEN 10 AND 19 THEN  '[10-19]'
                 WHEN @Ages BETWEEN 20 AND 29 THEN  '[20-29]'
                 WHEN @Ages BETWEEN 30 AND 39 THEN  '[30-39]'
                 WHEN @Ages BETWEEN 40 AND 49 THEN  '[40-49]'
                 WHEN @Ages BETWEEN 50 AND 59 THEN  '[50-59]'
                 WHEN @Ages BETWEEN 60 AND 69 THEN  '[60-69]'
                 WHEN @Ages BETWEEN 70 AND 79 THEN  '[70-79]'
                 WHEN @Ages BETWEEN 80 AND 89 THEN  '[80-89]'
                 WHEN @Ages BETWEEN 90 AND 99 THEN  '[90-99]'
                 WHEN @Ages>=100 THEN  '[100+]'  end  
RETURN @Age_Group
END
Run Code Online (Sandbox Code Playgroud)

当我用下面的例子测试时:

SELECT  [dbo].[Agebracket](10) 
Run Code Online (Sandbox Code Playgroud)

输出结果为[.

任何关于我能做什么的想法,因为我期望输出 [10-19]

Ala*_*ein 5

如果性能很重要,那么标量函数不适合您.内联表值函数(itvf)几乎总是表现更好.将Alexei发布的内容转换为itvf使得该功能在我的电脑上 6倍.让我来证明一下.首先,这是一个使用 CHOOSE的解决方案.我喜欢CHOOSE这里,因为它更干净(但不比老式的CASE声明快).

CREATE FUNCTION dbo.agebracket(@Ages tinyint) 
RETURNS VARCHAR(10) AS
BEGIN RETURN '['+(isnull(choose(@ages/10+1,'0-9','10-19','20-29','30-39',
             '40-49','50-59','60-69','70-79','80-89','90-99'),'100+'))+']' END
Run Code Online (Sandbox Code Playgroud)

请注意,我使用tinyint因为我们不想要负数而256就足以处理年龄(除非你在谈论国家,恐龙骨骼等)......

现在让我们将其重写为内联表值函数.

CREATE FUNCTION dbo.agebracket_itvf(@Ages tinyint) 
RETURNS TABLE AS RETURN 
SELECT ages = 
'['+(isnull(choose(@ages/10+1,'0-9','10-19','20-29','30-39',
             '40-49','50-59','60-69','70-79','80-89','90-99'),'100+'))+']';
Run Code Online (Sandbox Code Playgroud)

接下来是性能测试的一些示例数据.

if object_id('tempdb..#ageList') is not null drop table #ageList;
GO
create table #ageList (age tinyint);
insert #ageList
select top (1000000) abs(checksum(newid())%100)+1
from sys.all_columns a, sys.all_columns b;
Run Code Online (Sandbox Code Playgroud)

在我们测试之前,以下是您使用每个功能的方法:

-- scalar version
select top(10) t.age, ages = dbo.agebracket(t.age)
from #ageList t;

-- itvf version
select top(10) t.age, fn.ages
from #ageList t
cross apply dbo.agebracket_itvf(t.age) fn;
Run Code Online (Sandbox Code Playgroud)

结果:

age  ages
---- ----------
76   [70-79]
19   [10-19]
32   [30-39]
58   [50-59]
40   [40-49]
22   [20-29]
41   [40-49]
66   [60-69]
74   [70-79]
31   [30-39]    

age  ages
---- -------
76   [70-79]
19   [10-19]
32   [30-39]
58   [50-59]
40   [40-49]
22   [20-29]
41   [40-49]
66   [60-69]
74   [70-79]
31   [30-39]
Run Code Online (Sandbox Code Playgroud)

现在进行性能测试.

print 'scalar version'+char(13)+char(10)+replicate('-',50);
go
declare @st datetime = getdate(), @x varchar(10);
select @x = dbo.agebracket(t.age)
from #ageList t
print datediff(ms,@st,getdate());
GO 3

print 'itvf version'+char(13)+char(10)+replicate('-',50);
go
declare @st datetime = getdate(), @x varchar(10);
select @x = fn.ages
from #ageList t
cross apply dbo.agebracket_itvf(t.age) fn
print datediff(ms,@st,getdate());
GO 3
Run Code Online (Sandbox Code Playgroud)

这是结果.再次,itvf版本快了6倍!

scalar version
--------------------------------------------------
Beginning execution loop
2140
2167
2267
Batch execution completed 3 times.

itvf version 
--------------------------------------------------
Beginning execution loop
380
383
370
Batch execution completed 3 times.
Run Code Online (Sandbox Code Playgroud)