Existe-t-il un classement pour trier les chaînes suivantes dans l'ordre suivant 1,2,3,6,10,10A, 10B, 11?


12

J'ai une base de données avec une colonne VARCHAR qui contient des entiers de longueur variable. Je veux les trier pour que 10 vienne après 9, pas 1, et 70A après 70. J'ai pu le faire avec PATINDEX () , un CTE et des instructions CASE dans la clause WHERE.

Cependant, je me demandais s'il y avait une collation où cela serait inutile.


Voici le nouveau lien pour cette suggestion maintenant que Microsoft a migré de Connect vers UserVoice mais n'a pas transmis les URI: Supporte le "tri naturel" / DIGITSASNUMBERS comme option de collation
Solomon Rutzky

2
Microsoft a déclaré qu'il implémenterait cela en tant que fonctionnalité intégrée dans SQL Server s'ils obtenaient suffisamment de votes. Allez donc ici et cliquez sur le bouton de vote .
Peter Aylett

Réponses:


8

Non. Le classement concerne le tri alphabétique, en fonction de la page de code, de l'accent, de la casse, de la largeur et du kana. Les chiffres (0-9) n'ont aucune de ces propriétés.

Donc , 9est toujours après 10Bdans toute sorte.

Vous devez le diviser comme vous l'avez noté ou trier comme ceci:

ORDER BY
    RIGHT('                              ' + MyColumn, 30)

La longueur à droite détermine le nombre d'espaces dont vous disposez.

Vous pourriez bien sûr:

  • avoir 2 colonnes pour rendre cela inutile (et beaucoup plus rapide) et avoir une colonne calculée pour les combiner
  • insister sur des zéros non significatifs
  • justifier à droite dans un caractère (une version stockée de mon DROIT ci-dessus)

Les 2 dernières suggestions sont comme mon DROIT ci-dessus et légèrement différentes. Tri plus rapide (aucun traitement du colukmn requis) mais plus de stockage requis


je ne vois pas comment cela fonctionne. Ça casse pour 2, 2a, 3, etc ...
Mladen Prajdic

@Mladen Prajdic: vous avez raison, oups. Oublié les alphabétiques de fin
gbn

En ce qui concerne " Donc, 9c'est toujours après 10Bdans n'importe quel tri. ": C'est uniquement ainsi dans SQL Server car l'option de tri sous-jacente pour gérer "DigitsAsNumbers" n'a pas été exposée en tant qu'option de classement. Encore ;-). Cela est devenu disponible pour les applications Windows à partir de Windows 7, notamment dans l'Explorateur de fichiers. Et il peut un jour être exposé à SQL Server, si suffisamment de personnes soutiennent l'idée. J'ai essayé de faire bouger les choses en déposant la suggestion Connect suivante: Prise en charge du "tri naturel" / DIGITSASNUMBERS en tant qu'option de classement .
Solomon Rutzky

8

Je voudrais configurer une colonne calculée puis trier en fonction de cela. Quelque chose comme

CAST( 
     CASE WHEN IS_NUMERIC(left(OtherColumn, 2) = 1) then 
         left(OtherColumn,2) 
     else 
         left(otherColumn, 1)  
AS INT)

Utilisez ensuite cette colonne pour trier, car vous pouvez maintenant indexer la colonne.


C'est vraiment utile de savoir pour des problèmes similaires. Cependant, dans ce cas, je ne peux pas modifier le schéma.
Justin Dearing

Pouvez-vous ajouter au schéma? À moins d'une colonne calculée, vous pouvez toujours créer une vue - bien que cela ne soit pas vraiment optimisable comme une colonne calculée pourrait l'être.
Aaron Bertrand

Si vous effectuez une vue indexée et que vous avez l'édition Enterprise, votre requête utilisera automatiquement la vue indexée si elle peut comprendre ce que vous essayez de faire. Si l'édition standard vous devez utiliser WITH (NOEXPAND) pour déclencher la vue indexée à utiliser. À ce stade, vous devez avoir la déclaration de cas dans votre commande, mais cela devrait fonctionner, je pense.
mrdenny

Vous n'avez pas besoin de créer une colonne calculée. Vous pouvez utiliser cette expression directement dans la clause ORDER BY
a_horse_with_no_name

Si vous souhaitez garantir un index ou une analyse de table, vous pouvez le faire. Si vous souhaitez pouvoir indexer la valeur, une colonne calculée ou une vue indexée est nécessaire.
mrdenny

5

Si vous voulez un moyen douloureux de prouver ce que dit @gbn (essentiellement que vous ne pouvez pas dire à un classement de commander les sous-chaînes différemment), vous pouvez créer une table #temp rapide qui a un coefficient pour l'ordre que vous attendez, et voir si la commande par n'importe quel classement renvoie le même ordre:

CREATE TABLE #foo(id INT, n NVARCHAR(10));

CREATE TABLE #bar(collation SYSNAME);

SET NOCOUNT ON;

INSERT #foo SELECT 1,'1'
UNION SELECT 2,'2'
UNION SELECT 3,'3'
UNION SELECT 4,'6'
UNION SELECT 5,'10'
UNION SELECT 6,'10A'
UNION SELECT 7,'10B'
UNION SELECT 8,'11';

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'
    WITH x AS 
    (
        SELECT n, rn = ROW_NUMBER() OVER 
        (ORDER BY n COLLATE ' + name + ') FROM #foo
    ) 
    INSERT #bar 
    SELECT TOP (1) ''' + name + ''' FROM x
    WHERE NOT EXISTS
    (
        SELECT COUNT(*) FROM #foo AS f
        WHERE f.id = x.rn
        AND f.n <> x.n
    );' FROM sys.fn_helpcollations();

EXEC sp_executesql @sql;

SELECT collation FROM #bar;

GO
DROP TABLE #foo, #bar;

Cela s'exécute pour moi en environ 10 secondes et donne 0 lignes - ce qui signifie qu'aucun classement disponible pour SQL Server (au moins 2008 R2, n'a pas essayé Denali) triera de la manière que vous attendez. Vous avez besoin d'une manière différente de définir le tri.


2

Vous voulez un moyen sensé et efficace de trier les nombres en chaînes en tant que nombres réels? Envisagez de voter pour ma suggestion Microsoft Connect: Prise en charge du "tri naturel" / DIGITSASNUMBERS comme option de classement


Bien que cette question soit spécifique à SQL Server et que cette réponse ne le soit pas, je pensais que je devrais toujours publier ces informations simplement pour en faire prendre conscience et ne pas être en opposition avec les autres réponses.

Cela dit, en dehors de SQL Server, dans certains environnements, il est possible de faire ce type de tri. C'est quelque chose qui est au moins spécifié dans la documentation Unicode. Dans la norme / le rapport UNICODE LOCALE DATA MARKUP LANGUAGE (LDML) PART 5: COLLATION , il existe un graphique pour les paramètres de classement qui décrit diverses options pour personnaliser le comportement de tri. L'une des options est -kn-trueou [numericOrdering on]:

Si la valeur est sur , toute séquence de chiffres décimal (General_Category = Nd dans le [ UAX44 est trié à un niveau primaire avec sa valeur numérique]). Par exemple, "A-21" <"A-123". Les poids primaires calculés sont tous au début du groupe de réorganisation des chiffres . Ainsi, avec une table UCA non mise en mémoire, "a $" <"a0" <"a2" <"a12" <"a⓪" <"aa".

Cependant, ce document est une "norme technique" et ne fait pas partie de la spécification Unicode de base. Une note en haut du document indique:

Une norme technique Unicode (UTS) est une spécification indépendante. La conformité à la norme Unicode n'implique pas la conformité à un UTS.

Par conséquent, ce comportement particulier n'est pas disponible dans SQL Server ou même dans .NET (du moins pas nativement), même si les deux sont conformes à la spécification Unicode de base.

Le projet ICU (International Components for Unicode) est un ensemble de bibliothèques C / C ++ et Java qui implémente cette fonctionnalité, et il y a même une démonstration en ligne de celui-ci. Et sous "projets liés", il y a un lien vers un projet .NET qui semble être un wrapper d'objet COM pour la bibliothèque ICU qui permettrait à cette fonctionnalité d'être exposée au code managé. Mais il n'est pas clair si ce projet .NET est toujours actif.

Mais pour voir ce comportement en action, accédez à la démonstration de collation ICU .

Collez ce qui suit dans la zone de texte d' entrée sur le côté gauche:

1
2
10B
6
11
10A
3
10

Réglez toutes les options sur "par défaut". Cochez l'option "Entrer des numéros de ligne" à droite du sortbouton et assurez-vous que l'option "Diff forces" n'est pas cochée.

Cliquez sur le sortbouton et vous devriez récupérer ce qui suit:

[1] 1
[8] 10
[6] 10A
[3] 10B
[5] 11
[2] 2
[7] 3
[4] 6

C'est ce à quoi vous devez vous attendre lors d'un tri de chaîne typique et ce que vous voyez dans SQL Server.

Maintenant, dans la série de boutons radio juste au-dessus du sortbouton, la deuxième ligne est étiquetée "numérique". Sélectionnez le bouton radio "on".

Cliquez sortà nouveau sur le bouton et vous devriez récupérer ce qui suit:

[1] 1
[2] 2
[7] 3
[4] 6
[8] 10
[6] 10A
[3] 10B
[5] 11

Vous vous demandez si cela fonctionne lorsque la partie numérique est au milieu de la chaîne? Ok, collez ce qui suit dans la zone de texte d' entrée sur le côté gauche (en remplaçant la liste précédente):

Script - 1.sql
Script - 2.sql
Script - 10B.sql
Script - 6.sql
Script - 11.sql
Script - 10A.sql
Script - 3.sql
Script - 10.sql

Assurez-vous que le paramètre numérique est toujours défini sur "on". Cliquez sortà nouveau sur le bouton et vous devriez récupérer ce qui suit:

[1] Script - 1.sql
[2] Script - 2.sql
[7] Script - 3.sql
[4] Script - 6.sql
[8] Script - 10.sql
[6] Script - 10A.sql
[3] Script - 10B.sql
[5] Script - 11.sql

Vous voulez voir ça ailleurs? Créez un dossier sur votre disque dur, quelque chose comme C: \ temp \ sorting \ , et créez des fichiers vides de ces mêmes noms "Script -...". Faites un DIRdans une fenêtre de commande et vous verrez le tri standard. Mais lorsque vous regardez la liste des fichiers dans l'Explorateur Windows, vous verrez la liste triée en utilisant l'option "numérique" :-).


Pour info, Postgres 10 prend en charge les classements ICU. Voir cet article de blog de Peter Eisentraut.
Basil Bourque

@BasilBourque Merci d'avoir mentionné cela à propos de PG10. Ce billet de blog, à la fin, déclare que "ICU offre beaucoup de fonctionnalités dans ce domaine que nous n'exposons pas encore via PostgreSQL. Il existe des options pour le tri insensible à la casse, le tri insensible à l'accent et la personnalisation totale d'un classement. pour ceux des futures versions de PostgreSQL. " Donc, dans sa première mise en œuvre / actuelle, il ne modifie aucune des informations dans ma réponse. Si une future offre permet le tri numérique, je le mentionnerai dans ma réponse, mais comme note de bas de page, car cette question est spécifique à SQL Server.
Solomon Rutzky
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.