1
votes

UCanAccess en Java renvoyant un ordre incorrect avec la clause ORDER BY dans la colonne avec des caractères spéciaux

À l'aide de la base de données Microsoft Access (2007-2013) avec un fichier .mdb, j'ai créé une simple table test_table avec une seule colonne de texte "name" et j'ai inséré les valeurs de test suivantes:

fanatico
fanta
fantástico
fanático
obito
obituario
orbita
orbitando
óbito
órbita  

Lorsque SELECT * FROM test_table ORDER BY name la requête SELECT * FROM test_table ORDER BY name aide de la conception de requête MS Access, le résultat ordonné suivant est renvoyé:

fanatico,
fanático,
fanta,
fantástico,
obito,
óbito,
obituario,
orbita,
órbita,
orbitando

Cet ordre est totalement correct et attendu.

Maintenant, je dois récupérer et utiliser ces valeurs dans mon logiciel Java. Pour ce faire, j'utilise le pilote JDBC UCanAccess sur la version 5.0.0 pour 5.0.0 connecter à la base de données. La connexion elle-même est ouverte avec succès, mais, lorsque j'exécute la même requête ci-dessus, elle renvoie ce qui suit:

óbito,
fanatico,
orbita,
fanático,
fanta,
órbita,
fantástico,
obito,
obituario,
orbitando

Et ce n'est PAS le bon ordre (par exemple, óbito devrait venir immédiatement après obito ). L'ordre souhaité doit considérer les mots accentués comme s'ils étaient identiques au mot non centré équivalent.
Peu importe si óbito vient avant ou après obito , mais ils doivent être ensemble .
J'ai essayé d'utiliser COLLATE , essayé de changer le jeu de caractères, etc., mais rien n'a fonctionné. Quelqu'un a-t-il vécu quelque chose de similaire et pourriez-vous m'aider à résoudre ce problème? Merci d'avance.


0 commentaires

3 Réponses :


2
votes

Le pilote trie selon leur représentation binaire et / ou les caractères ASCII individuels. Les deux fournissent l'ordre de tri que vous avez fourni en bas. C'est entièrement un problème créé par le pilote, et les «correctifs» vont être limités.

Il existe une solution de contournement publiée dans le journal des modifications du pilote JDBC, sous les notes de version 2.0.9.3: WORKAROUND suggested: if you want the same behaviour of Access: select * from table2 order by orderJet( COLUMN1).

Si cela ne fonctionne pas, vous devez soit a) renverser le tri du pilote en créant / maintenir une colonne SORTORDER dans la base de données d'origine qui contient le même mot avec tous les caractères accentués supprimés, ou b) trouver un moyen de changer le tri après qu'il arrive du conducteur. Aucun de ces éléments n'est préférable, j'espère donc que la solution de contournement fournie par le développeur est suffisante.


2 commentaires

Avec votre réponse, la nouvelle requête générée était select * from test_table order by orderJet(name) , mais elle renvoie toujours le même ordre indésirable .... La solution "a)" est impossible car je ne peux pas modifier la base de données, mais seulement lire à partir de celui-ci. Le "b)" n'est pas impossible mais il n'est pas recommandé, car je traite généralement des millions de lignes.


@GuilhermeBarboza Vous pouvez utiliser un SELECT sans clause ORDER BY et faire le tri vous-même (ce qui déplace la tâche de tri du pilote vers votre code).



1
votes

Java par défaut n'effectue pas de comparaison de chaînes sensible aux paramètres régionaux. Dans votre exemple, j'ai essayé de suivre le programme exécuté comme ci-dessous pour un tri naturel

Output = [fanatico, fanático, fanta, fantástico, obito, óbito, obituario, orbita, órbita, orbitando]

la sortie est

Collections.sort(strings, Collator.getInstance(Locale.US));

Maintenant jut en remplaçant tri par la ligne ci-dessous

Output = [fanatico, fanta, fantástico, fanático, obito, obituario, orbita, orbitando, óbito, órbita]

Je reçois la sortie que vous attendez

 List<String> strings = Arrays.asList(new String[]{"óbito",
            "fanatico",
            "orbita",
            "fanático",
            "fanta",
            "órbita",
            "fantástico",
            "obito",
            "obituario",
            "orbitando"});
    
    Collections.sort(strings);
    System.out.println("Output = " + strings);

En vous donnant l'exemple ci-dessus pour comprendre la différence lorsque vous utilisez la comparaison de chaînes en utilisant la fonction locale. Il existe des moyens de gérer cela à partir de votre code ou de la configuration de la base de données.

Vous pouvez vérifier ici par exemple


1 commentaires

Je ne peux pas utiliser votre solution car je ne peux pas charger simultanément toutes les données de la base de données MS Access, car je traite des millions de lignes. La mémoire ne pourrait pas gérer toutes les informations.



0
votes

Avez-vous essayé d'appliquer un CharSet?

Jetez un œil iciCharSet pour MS Access '97 DB utilisant UCanAccess

private static java.sql.ResultSet executeDataTable(String sql) throws Exception {
    Class.forName("net.ucanaccess.jdbc.UcanaccessDriver");
    String conStr = "jdbc:ucanaccess://" + dataDir + "ABC.mdb";
    Properties props = new java.util.Properties();
    props.put("charSet", "Cp1252");
    java.sql.Connection con = java.sql.DriverManager.getConnection(conStr, props);

    java.sql.Statement stmt = con.createStatement();
    return stmt.executeQuery(sql);
}

Lorsque vous utilisez une connexion JDBC simple, vous pouvez essayer d'ajouter un paramètre de connexion:

class DatabaseOpener : JackcessOpenerInterface {
  override fun open(fl: File, pwd: String?): Database {
    return DatabaseBuilder.open(fl).apply {
      this.charset = charset("Cp1252")
    }
  }
}

// URL
"jdbc:ucanaccess://<path-to-mdb-file>;memory=false;jackcessOpener=${DatabaseOpener::class.qualifiedName!!}"


Vous devez vérifier ce que pourrait être votre jeu de caractères. Remplacez donc potentiellement «Cp1252».


1 commentaires

Alors, quel devrait être le jeu de caractères? J'ai essayé Cp1252 , ISO-8859-1 , UTF-8 , utf8 , utf8mb4 et utf8mb4_0900_ai_ci mais rien n'a fonctionné jusqu'à présent. Aucune exception n'a cependant été lancée.