IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Bases de données Delphi Discussion :

[SQLITE] [FireDAC] Recherche avec Diacritiques


Sujet :

Bases de données Delphi

  1. #1
    Nouveau membre du Club
    Inscrit en
    novembre 2002
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : novembre 2002
    Messages : 33
    Points : 31
    Points
    31
    Par défaut [SQLITE] [FireDAC] Recherche avec Diacritiques
    Bonjour
    je souhaite retrouver dans une base SQlite toutes les valeurs avec ET sans accents et autres diacritiques
    je cherche "Jérémy", je souhaiterais qu'un LIKE '%JEREMY%' me ramène jeremy, jérémy, JÉRÉMY...

    Mauvaise solution :
    Je le faisais précédemment avec Delphi 7 et les composants Zeos comme ceci :
    WHERE ((REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(author,'à','a'),'á','a'),'å','a'),'â','a'),'ä','a'),'ã','a'),'é','e'),'è','e'),'ë','e'),'ê','e'),'ì','i'),'í','i'),'î','i'),'ï','i'),'ò','o'),'ø','o'),'ô','o'),'ö','o'),'õ','o'),'ú','u'),'ù','u'),'ü','u'),'û','u'),'ý','y'),'ÿ','y') LIKE '%JEREMY%')
    OR (REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(author,'Á','A'),'Â','A'),'Ã','A'),'Ä','A'),'Å','A'),'È','E'),'É','E'),'É','E'),'Ê','E'),'Ë','E'),'Ì','I'),'Í','I'),'Î','I'),'Ï','I'),'Ì','I'),'Ò','O'),'Ó','O'),'Ô','O'),'Õ','O'),'Ö','O'),'Ù','U'),'Ú','U'),'Û','U'),'Ü','U') LIKE '%JEREMY%'))
    Cela fonctionnait... lentement! Je le mets dans le message pour servir éventuellement.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
    ////////////////////////////////////////////////////////////////////////////////
    // Pour créer les chaînes, avec la recherche en "aValue"
    function SqlReplace1(aValue: string): string;
    Var S1,S2,S3 : string;
        i : integer;
    begin
    S1 :='àáåâäãéèëêìíîïòøôöõúùüûýÿ';
    S2 :='aaaaaaeeeeiiiiooooouuuuyy';
    S3 :='' ;
    for i:= 1 to length(S1) do
       S3:=S3+'REPLACE(';
     S3:=S3+aValue;
    for i:= 1 to length(S1) do
       S3:=S3+','+quotedstr(S1[i])+','+quotedstr(S2[i])+')';
    result := S3+' ';
    end;
    ////////////////////////////////////////////////////////////////////////////////
    function SqlReplace2(aValue: string): string;
    Var S1,S2,S3 : string;
        i : integer;
    begin
     S1 :='ÁÂÃÄÅÈÉÉÊËÌÍÎÏÌÒÓÔÕÖÙÚÛÜ';
     S2 :='AAAAAEEEEEIIIIIOOOOOUUUU';
    S3 :='' ;
    for i:= 1 to length(S1) do
       S3:=S3+'REPLACE(';
     S3:=S3+aValue;
    for i:= 1 to length(S1) do
       S3:=S3+','+quotedstr(S1[i])+','+quotedstr(S2[i])+')';
    result := S3+' ';
    end;
    Problème actuel
    J'ai implémenté le code préconisé par RAD STUDIO et FireDAC
    (exemple : FireDAC.Phys.SQLite.TFDSQLiteCollation)
    et modifié le code en tenant compte de ce message (Epées et FireDac SQLite), mais ça ne fonctionne pas.
    J'ai modifié certains paramètres du composant sans succès.
    Voila le résultat, je voudrais avec les 3 recherches avec le mot "PERE"


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    procedure TForm1.FormCreate(Sender: TObject);
     
    begin
      with FDConnection do
        if Connected then Connected := False;
     
      SQLitePhysDriverLink:= TFDPhysSQLiteDriverLink.Create(nil);
      SQLiteCollation:= TFDSQLiteCollation.Create(nil);
     
      With SQLiteCollation do begin
        Active := False;
        DriverLink := SQLitePhysDriverLink;
        CollationName := 'UTF16NoCase';
        Flags := [sfLingIgnoreCase,sfLingIgnoreDiacritic,sfIgnoreCase];
        Active := True;
      end;
     
    {Ouverture de FDConnection après activation de SQLiteCollation }
      with FDConnection do begin
        Params.Add ('DriverID = SQLite');      {Inutile ici}
        Params.Add ('OpenMode = CreateUTF8');  {Idem}
        Connected := True;
      end;
    end;
     
    procedure TForm1.btnFindClick(Sender: TObject);
    begin
      sSql.Clear;
      sSql.add('SELECT CAST(AUTHOR_SORT AS varchar(255)) AS AUTEUR,');
      sSql.add('CAST(TITLE AS varchar(255)) AS TITRE');
      sSql.add('FROM "BOOKS" ');
      sSql.add('WHERE');
      sSql.Add('BOOKS.AUTHOR_SORT LIKE '+quotedstr('%'+edAuteur.Text+'%'));
      sSql.Add('ORDER BY AUTHOR_SORT, TITLE');
      memoOut.Lines.Assign(sSql);
      qryBooks.Open(sSql.Text);
      caption := inttostr(DSBooks.DataSet.recordcount);
    end;
    Merci de votre aide, ou de me dire si je suis dans la bonne direction au moins.

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    juillet 2006
    Messages
    11 923
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : juillet 2006
    Messages : 11 923
    Points : 20 867
    Points
    20 867
    Par défaut
    Il y a très longtemps, j'avais constitué un dictionnaire de mot pour aider un moteur de recherche avec une forme "tel que" et une forme majuscule sans accents et une sans accents sans ligature, 800000 mots pointant sur 6000 blocs de texte.
    Ligature soit comme dans cœur ou œdème
    ces 6000 textes faisant parti d'un thésaurus maintenu que lors d'un changement de version de ce dictionnaire, soit une fois par an. on pouvait donc se permettre ce choix technique

    Mais si l'on souhaite une recherche fulltext sans devoir générer un dictionnaire qui peut devenir très lourds si l'on n'a pas un ensemble "fini" de texte, j'ai codé un rapide recherche dans des XML récemment, je n'ai pas encore supporté la gestion des accents, ces XML pouvant varier d'une base à un autre, varier souvent, il est inenvisageable de maintenir un dictionnaire (même si via un jeu de TRIGGER cela sera faisable)

    Tu as repris l'exemple UTF16NoCase, je l'aurais appelé différemment mais cela ne doit pas avoir d'impact

    sfLingIgnoreDiacritic "Ignore linguistiquement les caractères sans espace." / "Linguistically ignore non-spacing characters." selon documentation
    Cela veut dire quoi sans espace ? une erreur pour pour accent ?
    une mauvaise reprise de sfIgnoreNonSpace ?

    Sinon dans ton SQL, tu ne devrais pas écrire ceci ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
      sSql.Text := 
        ' SELECT CAST(AUTHOR_SORT AS varchar(255)) AS AUTEUR) ' +
        ' CAST(TITLE AS varchar(255)) AS TITRE ' +
        ' FROM "BOOKS"  ' +
        ' WHERE BOOKS.AUTHOR_SORT LIKE '+quotedstr('%'+edAuteur.Text+'%')
        ' ORDER BY AUTHOR_SORT, TITLE ' +
        ' COLLATE UTF16NoCase ' ; // Faut bien lui dire si tu l'utilises ou pas cette collation
    J'ignore combien de colonne ta recherche doit supporter mais je tenterais l'astuce du TRIGGER, lors de la modification TITLE ou AUTHOR, je stockerais dans une colonne TITLE_C et AUTHOR_C une version épurée pour le moteur de recherche pour n'utiliser qu'un seul LIKE comme ci-dessus, l'avantage que l'on peut indexer les colonnes épurées donc améliorer la recherche

    Sinon faire LIKE OR LIKE, en passant la variante brute et la variante sans accent avec une comparaison insensible à la casse (soit par Collation soit par UPPER)
    Il y a plein d'approche, la volumétrie obligeant à faire des choix

    Voir aussi si tu peux utiliser un Paramètre, en SQL Server récemment, le Champ LIKE :pFilterValue en ADO AADOQuery.Parameters.ParamByName(AFilter.ParamName).Value := AFilter.FieldValue; est passé tout seul.
    Tu peux ainsi préparer la requête et bind avec différentes valeurs, encore du temps gagné
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Nouveau membre du Club
    Inscrit en
    novembre 2002
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : novembre 2002
    Messages : 33
    Points : 31
    Points
    31
    Par défaut
    Merci de la réponse.
    j'avais essayé avec le collate dans le select... puis enlevé car j'avais lu (où?) qu'un seul suffit et que celui dans le select est prioritaire.

  4. #4
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2007
    Messages
    12 479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2007
    Messages : 12 479
    Points : 33 659
    Points
    33 659
    Billets dans le blog
    42
    Par défaut
    Bonjour,

    AMHA le problème serait plutôt dans la clause WHERE.

    Voila le résultat, je voudrais avec les 3 recherches avec le mot "PERE"
    si je me fie à ces images écrans il s'agit plus d'un LOWER(TITLE) LIKE ....
    ensuite faudrait-il comprendre que la recherche est le cumul des 3 images ?

    [EDIT] je n'avais pas intégré le début de la discussion
    je souhaite retrouver dans une base SQlite toutes les valeurs avec ET sans accents et autres diacritiques
    je cherche "Jérémy", je souhaiterais qu'un LIKE '%JEREMY%' me ramène jeremy, jérémy, JÉRÉMY...

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     SELECT CAST(AUTHOR_SORT AS varchar(255)) AS AUTEUR,
                     CAST(TITLE AS varchar(255)) AS TITRE
                     FROM "BOOKS"
                     WHERE
                     BOOKS.AUTHOR_SORT LIKE '+quotedstr('%'+edAuteur.Text+'%'
                     ORDER BY AUTHOR_SORT, TITLE;
    pourquoi ces CAST et " " pour le nom de table ?

    j'aurais écrit la requête différement et utiliser une macro
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     SELECT AUTHOR_SORT  AUTEUR,
                                TITLE  TITRE
                     FROM BOOKS
                     &clausewhere
                     ORDER BY AUTHOR_SORT, TITLE;

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    ssql.close;
    if edtAuteur.text.isempty  // if Length(trim(edtauteur.text))=0
                 then  ssql.macrobyname('clausewhere').clear  
                 else   ssql.macrobyname('clauserwhere').asraw:='WHERE AUTHOR_SORT LIKE '+quotedstr('%'+edAuteur.Text+'%');
    ssql.Open();
    pour rependre un paramètre comme le suggère ShaiLetroll j'utiliserai
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     SELECT AUTHOR_SORT  AUTEUR,
                                TITLE  TITRE
                     FROM BOOKS
                     where Like(:parametre,AUTHOR_SORT)
                     ORDER BY AUTHOR_SORT, TITLE;
    car firedac ne sais pas traiter (à ma connaissance) le LIKE :parametre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    var like : String;
    like:='%'+edAuteur.Text+'%';
    ssql.Open('',[like]);


    Bien évidemment, pour moi, c'est le edAuteur.text que je traiterai pour les caractères accentués (je me demande d'ailleurs s'il n'y a pas une fonction toute faite pour ça)

    Encore un essai à programmer dans mon agenda du week-end
    La seule chose absolue dans un monde comme le nôtre, c'est l'humour. » Albert Einstein

    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) et peut être quelques autres
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  5. #5
    Nouveau membre du Club
    Inscrit en
    novembre 2002
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : novembre 2002
    Messages : 33
    Points : 31
    Points
    31
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    si je me fie à ces images écrans il s'agit plus d'un LOWER(TITLE) LIKE ....
    ensuite faudrait-il comprendre que la recherche est le cumul des 3 images ?
    Merci
    je précise ma démarche par rapport à la source de recherche.
    Il faut rentrer une liste de noms propres dans une table de noms sans faire de doublons.

    Les noms dans les deux listes peuvent être orthographiés avec ou sans diacritiques et majuscule :
    éric, eric, Eric, Éric par exemple. (et des noms étrangers avec des diacritiques non français : á, í, ö, ø... qui ont perdu leur diacritique d'un coté ou de l'autre)
    Je veux tous les trouver.
    Par principe mais je me trompe peut-être je filtre les diacritiques dans la source et je cherche "ERIC" pour trouver éric, eric, Eric, Éric.

    Pour filtrer les diacritiques, voici 2 fonctions qui peuvent être utiles. Faire un UPPERCASE éventuel.
    voir aussi sur ce forum: Enlever les accents d'une chaîne : solution
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
    Function DTStringRemoving(s:string):string;
    var i:integer;
    begin
     i:=1;
     while i<=length(s) do
      begin
       case s[i] of 'Œ','œ':begin
                             s[i]:='o';
                             insert('e',s,i+1);
                             inc(i);
                            end;
                    'Æ','æ':begin
                             s[i]:='a';
                             insert('e',s,i+1);
                             inc(i);
                            end;
                    'Š','š':s[i]:='s';
                    'Ç','ç':s[i]:='n';
                    'Ñ','ñ':s[i]:='n';
                    'Ð':s[i]:='d';
                    'Ÿ','Ý','ý','ÿ':s[i]:='y';
                    'À'..'Å','à'..'å':s[i]:='a';
                    'È'..'Ë','è'..'ë':s[i]:='e';
                    'Ì'..'Ï','ì'..'ï':s[i]:='i';
                    'Ò'..'Ö','Ø','ò'..'ö','ø':s[i]:='o';
                    'Ù'..'Ü','ù'..'ü':s[i]:='u';
         end;
       inc(i);
       end;
     Result:=s;
    end;
    // autre fonction windows
    function RemoveDiacritics(aValue: string): string;
     var
        Tmp :string;
        Len :integer;
        i   :Integer;
      begin
        Len := FoldString(MAP_COMPOSITE, PChar(aValue), -1, nil, 0);
        SetLength(Tmp, Len);
        FoldString(MAP_COMPOSITE, PChar(aValue), -1, PChar(Tmp), Len);
        Result := '';
        for i := 1 to Length(Tmp) do
          if IsCharAlphaNumeric(Tmp[i]) OR (Tmp[i] = ',') OR (Tmp[i] = ' ') then
             Result := Result +Tmp[i];
      end;

  6. #6
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2007
    Messages
    12 479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2007
    Messages : 12 479
    Points : 33 659
    Points
    33 659
    Billets dans le blog
    42
    Par défaut
    Re,
    Voilà ma curiosité a été piquée et du coup j'ai fait plusieurs essais

    tout d'abord une fonction pour ôter les accents (à améliorer)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function RemoveAccents(const WS: String): AnsiString;
    const
      CodePage = 20127; //20127 = us-ascii
    begin
      SetLength(Result, WideCharToMultiByte(CodePage, 0, PWideChar(WS),
        Length(WS), nil, 0, nil, nil));
      WideCharToMultiByte(CodePage, 0, PWideChar(WS), Length(WS),
        PAnsiChar(Result), Length(Result), nil, nil);
    end;
    par la suite j'ai lu ceci
    As specified in the documentation, the built-in LIKE and GLOB operators always uses the NOCASE or BINARY collation.
    https://www.sqlite.org/lang_expr.html#like
    Donc si j'en crois ceci le like ne tiendra pas compte d'une collation quelconque (que ce soit une déclarée au sein de SQLite ou du FDphysDriver), et,je confirme, LIKE est case insensitive par défaut

    j'ai donc tenté l'expérience en créant ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    procedure TForm3.compareprocedure(ASender: TObject; len1: Integer;
      str1: Pointer; len2: Integer; str2: Pointer; var AResult: Integer);
    begin
    showmessage('test');
    // je ne sais pas trop comment traiter str1,str2
    Aresult:=0;
    end;
     
    procedure TForm3.FDPhysSQLiteDriverLink1DriverCreated(Sender: TObject);
    begin
      SQLiteCollation:= TFDSQLiteCollation.Create(nil);
     
      With SQLiteCollation do begin
        Active := False;
        DriverLink := FDPhysSQLiteDriverLink1;
        CollationName := 'SANSACCENT';
        SQLiteCollation.CollationKind:=scCustomUTF16;  // appel à une collation particulière
        SQLiteCollation.OnCompare:=CompareProcedure; // procedure qui permet la comparaison 
        Active := True;
      end;
    end;
    Si je fait un SQL 'ORDER BY COLACCENT COLLATE SANSACCENT' je rentre bien dans ma procédure de comparaison
    par contre un 'WHERE COLACCENT COLLATE SANSACCENT LIKE ...' ne rentre pas dedans
    La seule chose absolue dans un monde comme le nôtre, c'est l'humour. » Albert Einstein

    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) et peut être quelques autres
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  7. #7
    Nouveau membre du Club
    Inscrit en
    novembre 2002
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : novembre 2002
    Messages : 33
    Points : 31
    Points
    31
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    Si je fait un SQL 'ORDER BY COLACCENT COLLATE SANSACCENT' je rentre bien dans ma procédure de comparaison
    par contre un 'WHERE COLACCENT COLLATE SANSACCENT LIKE ...' ne rentre pas dedans
    Toutes mes recherches de COLLATE menaient à des problèmes de tris avec accents (ORDER BY).
    COLLATE ne traite peut-être les recherches avec "where" ?

  8. #8
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2007
    Messages
    12 479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2007
    Messages : 12 479
    Points : 33 659
    Points
    33 659
    Billets dans le blog
    42
    Par défaut
    Citation Envoyé par JLGARIOUD Voir le message
    Toutes mes recherches de COLLATE menaient à des problèmes de tris avec accents (ORDER BY).
    COLLATE ne traite peut-être les recherches avec "where" ?
    je n'ai testé que le like qui est case insensitive, pas avec un where ce que je viens de tester avec mon brouillon de programme
    ma fonction de comparaison est appellés si j'écrit ce SQL
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT COLACCENT,lower(colaccent) FROM ACCENTS WHERE lower(COLACCENT COLLATE SANSACCENT)=:A
    c'est bien le LIKE qui ne veut rien savoir.

    La solution "simple" pour utiliser les LIKE serait d'avoir des colonnes sans accents comme l'avait suggéré ShaiLeTroll
    je stockerais dans une colonne TITLE_C et AUTHOR_C
    les autres serait en ajoutant des fonctions ou collections à SQLite (là j'avoue je patauge)
    La seule chose absolue dans un monde comme le nôtre, c'est l'humour. » Albert Einstein

    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) et peut être quelques autres
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  9. #9
    Nouveau membre du Club
    Inscrit en
    novembre 2002
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : novembre 2002
    Messages : 33
    Points : 31
    Points
    31
    Par défaut
    Merci pour toutes les réponses.
    Je vais utiliser la solution "simple" comme l'avait suggéré ShaiLeTroll : dupliquer la colonne.

    Je vais créer une nouvelle colonne AUTHOR_C
    Je vais dupliquer ma colonne (AUTHOR_SORT) dans cette colonne en filtrant (voir plus haut les fonctions)
    je chercherai dans la colonne sans diacritiques et afficherai la valeur originelle.
    Ca devrait marcher.

    Si quelqu'un de sympa pouvait me donner les commandes SQL, je ne pratique pas couramment
    Je vais tenter de le faire
    Je pourrais mettre la solution trouvée et "résolu".
    Merci à tous

  10. #10
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2007
    Messages
    12 479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2007
    Messages : 12 479
    Points : 33 659
    Points
    33 659
    Billets dans le blog
    42
    Par défaut
    Citation Envoyé par JLGARIOUD Voir le message
    Si quelqu'un de sympa pouvait me donner les commandes SQL, je ne pratique pas couramment
    Point de commande SQL sensu stricto pour le faire, il va falloir faire une moulinette pour l'existant style
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    begin
    fdquery1.open('select auth_sort,titre_sort from books');
    while not fdquery1.eof do
     begin
       FDConnection1.ExecSQL('UPDATE BOOKS SET auth_c=? AND Titre_C=? WHERE auth_c=? and titre_c=?',  // bien sur s'il y a une clé unique dans books c'est mieux ;)
                             [noaccent(fdquery1.FieldByName('auth_sort').asString),
                              fdquery1.FieldByName('auth_sort').asString,
                              noaccent(fdquery1.FieldByName('titre_sort').asString),
                              fdquery1.FieldByName('titre_sort').asString]);
       fdQuery1.Next;
     end;
    end
    et prevoir un évènement onbeforepost ou une autre solution quand on ajoute une ligne à la table
    La seule chose absolue dans un monde comme le nôtre, c'est l'humour. » Albert Einstein

    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) et peut être quelques autres
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  11. #11
    Nouveau membre du Club
    Inscrit en
    novembre 2002
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : novembre 2002
    Messages : 33
    Points : 31
    Points
    31
    Par défaut
    Merci
    Pour l'instant j'ai fait la création de colonne, d'après ce que j'ai lu - et constaté - "IF EXISTS" n'existe pas en SQLite.
    J'ai trappé l'erreur pour savoir si ça existe, pas très beau.
    je vais tester la recopie des colonnes.

  12. #12
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2007
    Messages
    12 479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2007
    Messages : 12 479
    Points : 33 659
    Points
    33 659
    Billets dans le blog
    42
    Par défaut
    Bonjour,
    Je n'avais pas fini
    Citation Envoyé par SergioMaster
    Les autres seraient en ajoutant des fonctions ou collections à SQLite (là j'avoue je patauge)
    Si pour la collection tous mes essais ont foirés puisque Like ne l'utilise pas, il restait la fonction. Après avoir lu dans le docwiki la partie qui s'y rapporte
    Extension du moteur SQLite
    Fonctions personnalisées

    SQLite ne supporte pas le concept de procédure stockée ou de fonction, car il autorise l'utilisation de l'environnement du langage de l'hôte pour étendre les fonctionnalités du moteur. SQLite autorise le recensement des fonctions de langage de l'hôte dans le moteur SQLite et leur utilisation dans les commandes SQLFiredacAC simplifie ce processus en introduisant le composant TFDSQLiteFunction.
    Je vais me lancer dans cette nouvelle exploration.

    C'est encore très "brouillon"


    j'ai déposé sur ma forme un TFDPhysSQLiteDriverLink et, c'est là un composant dont je ne connaissais pas l'existance, un TFDSQliteFunction.
    J'ai rempli les diverses propriétés et créé l'évènement on calculate
    Nom : Capture.PNG
Affichages : 43
Taille : 10,4 Ko

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    procedure TForm3.FDSQLiteFunction1Calculate(AFunc: TSQLiteFunctionInstance;
      AInputs: TSQLiteInputs; AOutput: TSQLiteOutput; var AUserData: TObject);
    var
     K: TArray<Byte>;
     S : String;
    begin
      S:=LowerCase(S);
      S:=Ainputs[0].AsWideString;
      S:=StringReplace(S,'œ','oe',[rfReplaceAll]);
      S:=StringReplace(S,'æ','ae',[rfReplaceAll]);
      K := TEncoding.Convert(TEncoding.Unicode, TEncoding.ASCII, TEncoding.Unicode.GetBytes(S));
      AOutput.AsWideString := StringOf(K);
    end;
    un test sur une query simple sur mon "jeu d'essai"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    fdquery1.open('select colaccent,sansaccent(colaccent) sans from  accents');
    Nom : Capture_1.PNG
Affichages : 43
Taille : 2,9 Ko
    me confirme que cela fonctionne

    une recherche avec la clause like devient donc
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    FDQuery1.Open('SELECT COLACCENT FROM ACCENTS WHERE like(:a,sansaccent(COLACCENT))',['%'+oteraccent(edit1.text)+'%']);
    // oteraccent est le même algorithme que dans FDSQLiteFunction1Calculate
    et devine quoi cela fonctionne parfaitement, pas de colonne supplémentaire dans la table

    c'est encore brouillon car j'ai deux fois la même fonction de conversion fortement inspirée de celle de Papy214 (j'ai juste ajouté deux ligatures), et ma tentative de création d'un TFDSQliteFunction au runtime ne fonctionne pas, mais, bon, je ne vais pas non plus tout faire

    * nécessite l'utilisation de Firedac.Phys.SQLiteWrapper

    P.S.
    "IF EXISTS" n'existe pas en SQLite.
    pour les tables si, j'en suis sûr CREATE TABLE IF NOT EXISTS test_col (f1 VARCHAR(10)).
    Pour les colonnes par contre joker je vois deux solutions pour tester si la colonne existe
    cf PRAGMA
    avec ce SQL
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    pragma table_info(books) // pas de clause where possible
    ou l'utilisation de TFDMetaInfoQuery
    ou l'utilisation (plus simple) de TFDMetaInfoQuery metainfokind=mkTableFields en gros fait le même SQL
    La seule chose absolue dans un monde comme le nôtre, c'est l'humour. » Albert Einstein

    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) et peut être quelques autres
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  13. #13
    Nouveau membre du Club
    Inscrit en
    novembre 2002
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : novembre 2002
    Messages : 33
    Points : 31
    Points
    31
    Par défaut
    Merci, super, j'ai réussi à le faire fonctionner.
    grâce à toi !
    Je n'ai pas utilisé ta requête :
    FDQuery1.Open('SELECT COLACCENT FROM ACCENTS WHERE like(:a,sansaccent(COLACCENT))',['%'+oteraccent(edit1.text)+'%']);
    // oteraccent est le même algorithme que dans FDSQLiteFunction1Calculate
    Il y a une erreur d'argument semble-t-il et comme je suis par expert en syntaxe, j'ai fait ce que je savais faire :
    SELECT TITLE FROM BOOKS WHERE sansaccent(TITLE) LIKE ' + quotedstr('%' + UpperCase(RemoveAccents(edTitre.Text) + '%')));
    Mais la fonction "FDSQLiteFunction" marche bien, je l'ai changée pour avoir plus de caractères et joins le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
     
    // il y a deux fonctions pour enlever les diacritiques 
    //puis le lancement
     
    function RemoveAccents(const WS: String): AnsiString;
    const
      CodePage = 20127; //20127 = us-ascii
    begin
      SetLength(Result, WideCharToMultiByte(CodePage, 0, PWideChar(WS),
        Length(WS), nil, 0, nil, nil));
      WideCharToMultiByte(CodePage, 0, PWideChar(WS), Length(WS),
        PAnsiChar(Result), Length(Result), nil, nil);
    end;
     
    procedure TForm1.FDSQLiteFunctionCalculate(AFunc: TSQLiteFunctionInstance;
      AInputs: TSQLiteInputs; AOutput: TSQLiteOutput; var AUserData: TObject);
    var
      K: TArray<Byte>;
      S: String;
      i: integer;
    begin
      S := AInputs[0].AsWideString;
      i := 1;
      while i <= Length(S) do
      begin
        case S[i] of
          'Œ', 'œ':
            begin
              S[i] := 'o';
              insert('e', S, i + 1);
              inc(i);
            end;
          'Æ', 'æ':
            begin
              S[i] := 'a';
              insert('e', S, i + 1);
              inc(i);
            end;
          'Š', 'š':
            S[i] := 's';
          'Ç', 'ç':
            S[i] := 'n';
          'Ñ', 'ñ':
            S[i] := 'n';
          'Ð':
            S[i] := 'd';
          'Ÿ', 'Ý', 'ý', 'ÿ':
            S[i] := 'y';
          'À' .. 'Å', 'à' .. 'å':
            S[i] := 'a';
          'È' .. 'Ë', 'è' .. 'ë':
            S[i] := 'e';
          'Ì' .. 'Ï', 'ì' .. 'ï':
            S[i] := 'i';
          'Ò' .. 'Ö', 'Ø', 'ò' .. 'ö', 'ø':
            S[i] := 'o';
          'Ù' .. 'Ü', 'ù' .. 'ü':
            S[i] := 'u';
        end;
        inc(i);
      end;
      AOutput.AsWideString := UpperCase(S); // inutile avec LIKE
    end;
     
    procedure TForm1.btnFindFnctClick(Sender: TObject);
    begin
      FDSQLiteFunction.DriverLink := FDPhysSQLiteDriverLink;
      FDSQLiteFunction.FunctionName := 'sansaccent';
      FDSQLiteFunction.ArgumentsCount := 1;
      FDSQLiteFunction.Active := true;
      FDSQLiteFunction.OnCalculate := FDSQLiteFunctionCalculate;
      sSql.Clear;
      sSql.Add('SELECT TITLE FROM BOOKS WHERE sansaccent(TITLE) LIKE ' +
        quotedstr('%' + UpperCase(RemoveAccents(edTitre.Text) + '%')));
      MemoOut.Lines.Assign(sSql);
      qryBooks.Open(sSql.Text);
      caption := 'Trouvés : ' + inttostr(DSBooks.DataSet.recordcount);
    end;

  14. #14
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2007
    Messages
    12 479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2007
    Messages : 12 479
    Points : 33 659
    Points
    33 659
    Billets dans le blog
    42
    Par défaut
    Citation Envoyé par JLGARIOUD Voir le message
    Il y a une erreur d'argument semble-t-il et comme je suis par expert en syntaxe
    il faut simplement respecter ce que j'ai écrit
    pour faire simple la syntaxe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      FDQuery.Open(SQL,[parametres])
    Or tu as dû tenté
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SQL:='SELECT TITLE FROM BOOKS WHERE like('+quotedstr('%' + UpperCase(RemoveAccents(edTitre.Text) + '%'),TITLE)
    Query1.Open(SQL); // cela ne peut fonctionner,
    il faut écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SQL:='SELECT TITLE FROM BOOKS WHERE like(:a,TITLE)';
    Query1.Open(SQL,['%' + UpperCase(RemoveAccents(edTitre.Text) + '%']);
    mon "brouillon" amélioré

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    uses  ..  Firedac.Phys.SQLiteWrapper, ...;
    ...
          procedure FDPhysSQLiteDriverLink1DriverCreated(Sender: TObject);
      private
        { Déclarations privées }
    //   SQLitePhysDriverLink: TFDPhysSQLiteDriverLink;
       SQLiteCollation : TFDSQLiteCollation;
       aFDSQLiteFunction : TFDSQLiteFunction;
       procedure compareprocedure (ASender: TObject; len1: Integer;
        str1: Pointer {utf8/utf16}; len2: Integer; str2: Pointer {utf8/utf16};
        var AResult: Integer);
       procedure SQLsansAccent(AFunc: TSQLiteFunctionInstance;
          AInputs: TSQLiteInputs; AOutput: TSQLiteOutput; var AUserData: TObject);
       public
        { Déclarations publiques }
      end;
    function oteAccent(const WS: String): AnsiString;
    var  K: TArray<Byte>;
         S : String;
    begin
      S:=LowerCase(WS);
      S:=StringReplace(S,'œ','oe',[rfReplaceAll]);
      S:=StringReplace(S,'æ','ae',[rfReplaceAll]); 
     // autres ligatures ?
      K := TEncoding.Convert(TEncoding.Unicode, TEncoding.ASCII, TEncoding.Unicode.GetBytes(S));
      result:=StringOf(K);
    end;
     
    procedure TForm3.Button1Click(Sender: TObject);
    begin
    label1.Caption:=lowercase(oteaccent(edit1.Text));
    if length(Trim(edit1.Text))=0
     then FDQuery1.Open('SELECT TITLE FROM BOOKS ORDER BY TITLE') // COLLATE montri')
     else begin
            var SQL:String:='SELECT COLACCENT FROM ACCENTS WHERE like(:a,sansaccent2(COLACCENT))';
            FDQuery1.Open('SELECT TITLE FROM BOOKS WHERE like(:a,oteAccent(edit1.text)',['%'+oteAccent(edit1.text)+'%']);
     end;
    end;
     
    procedure TForm3.FDPhysSQLiteDriverLink1DriverCreated(Sender: TObject);
    begin
    // création au runtime 
    aFDSQLiteFunction:=TFDSQLiteFunction.Create(Self);
    aFDSQLiteFunction.DriverLink:=FDPhysSQLiteDriverLink1;
    aFDSQLiteFunction.OnCalculate:=SQLsansAccent;
    aFDSQLiteFunction.FunctionName:='sansaccent';
    aFDSQLiteFunction.ArgumentsCount:=1;
    aFDSQLiteFunction.Active:=True;
    end;
     
    procedure TForm3.SQLsansAccent(AFunc: TSQLiteFunctionInstance;
      AInputs: TSQLiteInputs; AOutput: TSQLiteOutput; var AUserData: TObject);
    begin
    Aoutput.asWideString:=OteAccent(Ainputs[0].AsWideString);
    end;
    Ne pas oublié le
    La seule chose absolue dans un monde comme le nôtre, c'est l'humour. » Albert Einstein

    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) et peut être quelques autres
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. SQLite+Firedac, problème avec des strings !
    Par SergioMaster dans le forum Bases de données
    Réponses: 3
    Dernier message: 27/05/2016, 12h57
  2. Recherche avec des accents!?
    Par mona dans le forum Access
    Réponses: 3
    Dernier message: 14/06/2005, 21h36
  3. Recherche avec Locate option lopartialKey
    Par jeje.r dans le forum Bases de données
    Réponses: 3
    Dernier message: 13/04/2005, 17h12
  4. recherche avec findnearest
    Par souad26 dans le forum Bases de données
    Réponses: 2
    Dernier message: 18/11/2004, 21h58
  5. Enlever la surbrillance lors d'une recherche avec vi
    Par sekiryou dans le forum Applications et environnements graphiques
    Réponses: 8
    Dernier message: 04/03/2004, 14h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo