T-SQL是否有能力对字符串进行自定义比较(用于排序),相当于.NET的IComparer
?
能够给Order By
一个用户定义函数的能力,它接受2个字符串并返回一个表示它们如何比较的值(大于,小于,等于)?
我目前有一个C#ICompararer
实现,用于对代码中的内容进行排序,但现在我需要从存储过程中生成相同的排序输出。
作为参考,这是我试图在TSQL中实现的IComparer
。
public class SemanticComparer : IComparer<string>
{
private static Regex _splitter = new Regex("\\W+");
public int Compare(string x, string y)
{
string[] partsX = _splitter.Split(x);
string[] partsY = _splitter.Split(y);
int shortest = Math.Min(partsX.Length, partsY.Length);
for (int index = 0; index < shortest; index++)
{
int intX, intY;
int result;
if (int.TryParse(partsX[index], out intX) && int.TryParse(partsY[index], out intY))
{
result = intX.CompareTo(intY);
}
else
{
result = string.Compare(partsX[index], partsY[index], StringComparison.Ordinal);
}
if (result != 0)
{
return result;
}
}
return 0;
}
}
它需要能够对看起来像这样的东西进行排序(按照它们应该输出的顺序):
每个非单词字符将字符串拆分为段,如果可能,尝试以数字方式对它们进行比较,如果不是,则尝试作为字符串。段数可以有任何“深度”。
不幸的是,CLR存储过程不是一种选择。
答案 0 :(得分:2)
with data as (
select c from (values
('9.1'), ('9.2'), ('9.2.1'), ('9.02.2'), ('9.02.3'), ('9.3'), ('9.3.1'), ('9.3.2'),
('10.'), ('11.'), ('11.1'), ('11.2.a'), ('11.2.b'), ('11.2.c'), ('11a.2.a'), ('11b.2.b')
) t(c)
)
select c, '[' +
right('00000' +
substring(c, 1, charindex('.', c + '.0.0', 1) - 1) +
case when substring(c + '.0.0', charindex('.', c + '.0.0', 1) - 1, 1) between '0' and '9' then ' ' else '' end,
6
) + '.' +
right('00000' +
substring(c, charindex('.', c + '.0.0', 1) + 1, charindex('.', c + '.0.0', charindex('.', c + '.0.0', 1) + 1) - charindex('.', c + '.0.0', 1) - 1) +
case when right('0' +
substring(c, charindex('.', c + '.0.0', 1) + 1, charindex('.', c + '.0.0', charindex('.', c + '.0.0', 1) + 1) - charindex('.', c + '.0.0', 1) - 1),
1
) between '0' and '9' then ' ' else '' end,
6
) + '.' +
right('00000' +
substring(c, charindex('.', c + '.0.0', charindex('.', c + '.0.0', 1) + 1) + 1, 10) +
case when right('0' +
substring(c, charindex('.', c + '.0.0', charindex('.', c + '.0.0', 1) + 1) + 1, 10),
1
) between '0' and '9' then ' ' else '' end,
6
) + ']'
from data
order by 2;
我把它扔在一起很有趣。正如您所看到的,SQL中的字符串解析通常需要大量工作并且有很多重复的子表达式。
这里的想法是,您可以通过常规字母排序以 排序的规范化格式转换您的值。前面的数字部分是零填充的。在每个“字段”的末尾允许单个字母字符,否则附加空格。例如,11.2.a
成为[00011 .00002 .00000a]
它相当灵活,你当然可以在标量函数中包含这个逻辑。我会让你决定这件事是不是一个好主意。
http://rextester.com/LYL6977(略有改进?)