我正在SQL Server 2008 R2中编写用户定义函数(UDF)。我想让UDF在不同的调用中使用不同的排序规则。这可能吗?是否可以根据用户输入动态更改排序规则?
从Intellisense,我在网上找不到什么,似乎必须在实际的T-SQL代码中指定排序规则,并且不能将其应用为变量或输入参数。有没有解决方法,特别是可以在UDF中使用的方法?
编辑:根据要求,这是我正在使用的UDF。我的目的是在有和没有" xxxx敏感"用于按照"相关性"
对查询结果进行排序的设置/*
T-SQL Implementation of Levenshtein Edit Distance.
*/
CREATE FUNCTION [dbo].[LevenshteinDistanceSQL] (
@textA varchar(max)
, @textB varchar(max)
)
RETURNS INT
AS
Begin
DECLARE
@aLength int
, @bLength int
, @prevSize int
, @currentSize int
, @previousDistances varbinary(max)
, @currentDistances varbinary(max)
, @result int
SET @aLength = LEN(@textA)
SET @bLength = LEN(@textB)
SET @result = NULL
-- Degenerate Cases
-- want calling routine to specify the collation of this comparison
If (@textA = @textB) SET @result = 0;
If (@aLength = 0) SET @result = @bLength;
If (@bLength = 0) SET @result = @aLength;
If (@result IS NULL)
Begin
-- Set sizes of tables to length of largest input text, plus 1
SET @prevSize = CASE WHEN @aLength > @bLength THEN @aLength ELSE @bLength END + 1;
SET @currentSize = CASE WHEN @aLength > @bLength THEN @aLength ELSE @bLength END + 1;
-- Initialize Previous distances
DECLARE
@i int
, @j int
, @cost int
, @curDistLastCost int
, @prevDistCurCost int
, @prevDistLastCost int
, @charA char(1)
, @charB char(1)
SET @i = 0
SET @previousDistances = 0x -- empty varbinary
While (@i < @prevSize)
Begin
SET @previousDistances = @previousDistances + CONVERT(binary(4), @i)
SET @i = @i + 1;
End
-- Process @textA
SET @i = 0
While (@i < @aLength)
Begin
SET @currentDistances = CONVERT(binary(4), @i + 1);
-- Process @textB
SET @j = 0
While (@j < @bLength)
Begin
SET @charA = SUBSTRING(@textA, @i + 1, 1)
SET @charB = SUBSTRING(@textB, @j + 1, 1)
-- want calling routine to specify the collation of this comparison
SET @cost = CASE WHEN @charA = @charB THEN 0 ELSE 1 END;
SET @curDistLastCost = CONVERT(int, SUBSTRING(@currentDistances, @j * 4 + 1, 4))
SET @prevDistCurCost = CONVERT(int, SUBSTRING(@previousDistances, (@j + 1) * 4 + 1, 4))
SET @prevDistLastCost = CONVERT(int, SUBSTRING(@previousDistances, @j * 4 + 1, 4))
SET @currentDistances = @currentDistances + CONVERT(binary(4), CASE
WHEN @curDistLastCost < @prevDistCurCost AND @curDistLastCost < @prevDistLastCost THEN @curDistLastCost + 1
WHEN @prevDistCurCost < @curDistLastCost AND @prevDistCurCost < @prevDistLastCost THEN @prevDistCurCost + 1
ELSE @prevDistLastCost + @cost
END)
SET @j = @j + 1
End
-- copy current distances to previous distances for next iteration
SET @previousDistances = @currentDistances
SET @i = @i + 1;
End
SET @result = CONVERT(int, SUBSTRING(@currentDistances, @bLength * 4 + 1, 4))
End
RETURN @result
End
这样称呼:
declare @text varchar(50)
set @text = 'c'
select
*
from
Skills as s
where
s.Name like '%' + @text + '%'
order by
dbo.LevenshteinDistance(@text, s.Name) -- COLLATE Latin1_General_100_CI_AI
, dbo.LevenshteinDistance(@text, s.Name) -- COLLATE Latin1_General_100_CS_AS_KS_WS
, s.Name
能够指定排序规则将允许我将最短的编辑距离(不敏感)排序到结果的顶部;在不敏感的编辑距离内,大小写,重音等匹配将位于顶部。
答案 0 :(得分:1)
有两种方法可以实现这一点,并且都需要SQLCLR。如您所见,T-SQL不允许动态指定COLLATION,但在.Net中您可以:)。事实上,为此目的使用SQLCLR还有两个好处:
您可以更精细地控制进行比较的选项。查看CompareOptions枚举。例如,它有一个IgnoreSymbols
选项:
表示字符串比较必须忽略符号,例如空格字符,标点符号,货币符号,百分号,数学符号,符号等。
SQLCLR UDF可以允许并行执行计划,而T-SQL UDF将始终禁止并行计划。为了允许并行计划,SQLCLR UDF需要是确定性的和标记为IsDeterministic=true
,并且不进行任何数据访问(不需要明确标记,因为它是默认值)。
那就是说,这里有一些补充说明:
我见过的Levenshtein距离算法的所有实现都假定有序比较(即任何*_BIN
归类)。但我想,你想要实现的目标可能会很有趣:)
考虑到您要完成的任务,在采用SQLCLR方法时,您实际上并不需要传递任何整理信息。原因是每种特定语言(即校对)都控制了相等和排序的比较选项。但Levenshtein距离算法不涉及排序。这减少了仅需两种变化的需求:
完全不敏感(至少对于IgnoreCase
和IgnoreNonSpace
,以及对IgnoreKanaType
,IgnoreSymbols
和IgnoreWidth
完全敏感(即Ordinal
)
所以,你的两个选择是:
在.Net中完成此操作:
在C#(或VB.Net)中完全实现算法并使用CompareInfo.Compare (String, String, CompareOptions)方法。在这种情况下,您需要两个功能,一个是&#34;敏感&#34;和#34;不敏感&#34;或两者的单个函数,它为@SensitiveComparison接受输入参数(可能是SqlBoolean)。但是要比较的字符串的特定语言是无关紧要的,所以你在技术上支持第1天的所有语言:)。
将算法保留在T-SQL中。在这种情况下,您将使用SqlCommand
的连接字符串执行"Context Connection = true;"
。您的函数将采用SqlString
的校对名称,并使用它来连接到进行比较的两个点中的算法。 [对于完全C#选项,我没有看到这个选项有多大好处,事实上它应该稍微慢一些,因为.Net代码对于这类事情应该更快。] < / p>
在任何一种情况下,都应该注意,这可以在标有PERMISSION_SET = SAFE
的程序集中完成。这意味着,在实现此功能时存在绝对没有安全风险(如此处所述)。并且,对于仍然存在(错误)SQLCLR /启用CLR集成本身存在安全风险的人,我写了一篇文章(SQLCLR系列文章的一部分),从不同角度和大量的角度介绍了这个安全主题。自己测试的例子:Stairway to SQLCLR Level 3: Security (General and SAFE Assemblies)(需要免费注册)。