2009-08-24 8 views
0

J'ai une colonne dans SQL Server 2005 qui stocke un numéro de version comme une chaîne que je voudrais trier. J'ai été incapable de trouver comment trier cette colonne, bien que je devine que ce serait une sorte de fonction de coutume ou de comparer l'algorithme.Fonction de tri personnalisée - de SQL Server

Quelqu'un peut-il me diriger dans la bonne direction de l'endroit où commencer? Je peux googler les mauvaises choses.

Vive

Tris

+1

Quel format est-il stocké exactement? – gbn

Répondre

2

J'utiliser des colonnes séparées int (par exemple MajorCol + MinorCol si vous suivez les versions majeures + mineures) et exécuter quelque chose comme

order by MajorCol, MinorCol 

dans ma requête.

1

je chercherais à l'aide d'une colonne calculée persistante qui traite la chaîne en un int ou une chaîne ou quelque chose d'approprié pour le tri dans le genre natif SQL Server - à savoir

'1.1.1.1' -> '001.001.001.001' 
'10.10.10.10' -> '010.010.010.010' 
'1.10.1.10' -> '001.010.001.010' 

Pour que vous puissiez trier par la colonne calculée et obtenir les résultats attendus. Sinon, vous pouvez utiliser une telle opération en ligne, mais elle peut être très lente. De plus, les fonctions UDF scalaires sont extrêmement lentes.

+0

Je commence à me demander si le stockage des informations de version dans les colonnes int séparées peut être le chemin à parcourir. –

0

La création d'une fonction SQL CLR est la solution idéale. Ils sont extrêmement rapides et puissants. Ce serait rapide et efficace car vous n'auriez pas à changer de code existant, et vous pourriez spécifier toutes les informations dont vous avez besoin directement dans vos instructions SQL.

La fonction SQL CLR peut accepter une chaîne d'entrée, ainsi que d'autres paramètres spécifiant l'information que vous souhaitez extraire de la chaîne d'entrée. Vous pouvez ensuite trier les valeurs de retour de la fonction. En particulier, je créerais une fonction générique qui accepte trois paramètres: une chaîne d'entrée, une expression régulière et un nom de groupe. Cette fonction vous permet de passer votre champ de base de données et une expression régulière avec des groupes nommés directement dans l'instruction SQL. La fonction SQL CLR créait une expression régulière, la testait par rapport à la chaîne et renvoyait finalement la valeur du groupe correspondant ou null s'il n'y avait pas de correspondance ou si le groupe ne correspondait pas (si le groupe était facultatif). Idéalement, vous voudriez passer la même expression régulière à chaque appel (peut-être en tant que variable comme @regex), pour profiter de toute mise en cache CLR de l'expression régulière compilée. Le résultat final serait très flexible et rapide.

Les options d'expressions régulières peuvent être spécifiées en ligne dans le modèle comme ceci: "(? Imnsx-imnsx: sous-expression)". Voir: msdn.microsoft.com/en-us/library/yd1hzczs.aspx

Le code pour une telle fonction ressemblerait à quelque chose comme ceci:

[SqlFunction(IsDeterministic=true,IsPrecise=true,DataAccess=DataAccessKind.None,SystemDataAccess=SystemDataAccessKind.None)] 
public static SqlString RegexMatchNamedGroup(SqlChars input, SqlString pattern, SqlString group_name) 
    { 
     Regex regex = new Regex(pattern.Value); 
     Match match = regex.Match(new string(input.Value)); 
     if (!match.Success) //return null if match failed 
      return SqlString.Null; 
     if (group_name.IsNull) //return entire string if matched when no group name is specified 
      return match.Value; 
     Group group = match.Groups[group_name.Value]; 
     if (group.Success) 
      return group.Value; //return matched group value 
     else 
      return SqlString.Null; //return null if named group was not matched   
    } 

Votre instruction SQL pouvez alors trier sur des morceaux de vos informations comme ceci:

declare @regex nvarchar(2000) = '^(?<Major>\d{1,3})\.(?<Minor>\d{1,3})'; 

select VersionNumber 
from YourTable 
order by 
Cast(RegexMatchNamedGroup(VersionNumber, @regex, 'Major') as int), 
Cast(RegexMatchNamedGroup(VersionNumber, @regex, 'Minor') as int) 
Questions connexes