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

Langage SQL Discussion :

[tous SGBDR] Syntaxe totale et complète d'une requête SQL


Sujet :

Langage SQL

  1. #1
    Expert éminent sénior
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 361
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 361
    Points : 20 386
    Points
    20 386
    Par défaut [tous SGBDR] Syntaxe totale et complète d'une requête SQL
    bonjour désolé si le titre du sujet semble ambigu.

    le contexte


    je suis en train de développer un projet de client-serveur ( à vocation commerciale si possible ) avec un moteur d'ordres SQL.
    La connection avec les bases de données se fait pour le moment via ODBC ( les accès natifs par la suite...).
    Dans mon projet, l'utilisateur aura la possibilité notamment d'afficher une console pour taper des ordres SQL.
    Puis une fonctionnalité pour créer des tables.

    problème numéro 1 rencontré

    si je crée une connection sur un fichier .mdb Access et que dans mon code source j'exécute SELECT * FROM NOM_TABLE pas de problèmes ça fonctionne bien.

    Avec MySQL il faut donner le nom de schéma apparemment sinon avec le simple nom de table j'ai une erreur.
    Si dans mon code source ( en C++ ) j'exécute, SELECT * FROM nom_schema.nom_table ça fonctionne, avec select * from nom_table =>erreur .
    D'après ce que je sais il y a aussi le nom de catalogue

    Donc est-ce que la syntaxe totale d'un ordre ( pour mon moteur interne ) est nom_catalogue.nom_schema.nom_table ?
    Par exemple nom_catalogue.nom_schema.nom_table afin que cela marche à coups sûrs sous tous les SGBDR ?

    problème numéro 2

    dans une table particulière l'utilisateur peut enregistrer les requêtes qu'il saisit ça fait partie des fonctionnalités du projet.
    L'enregistrement se fait grâce à un INSERT
    Le problème demeure pour les chaînes de caractêres.
    En termes simles si l'utilisateur veut enregistrer SELECT * FROM tbl_clients WHERE nom_client='DUPONT' moi de mon côté dans mon code source je construits un ordre d'exécution

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    SELECT INTO table_ordres_SQL VALUES ( ' SELECT * FROM tbl_clients WHERE nom_client='DUPONT' ')
    et j'ai un message d'erreur à cause des caractères apostrophe.

    J'ai pensé , par code, analyser la requête , et remplacer le caractère apostrophe par le signe @.

    Ce qui va donner au final
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    SELECT INTO table_ordres_SQL VALUES ( ' SELECT * FROM tbl_clients WHERE nom_client=@DUPONT@ ')

    Est ce que c'est une bonne méthode ( risques sous Oracle ou MS-SQL Server ? ) ou faut-il prendre un autre caractêre , non réservé par le SGBDR ?

    Merci pour les réponses.

  2. #2
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 154
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Problème numéro 1 :
    Selon les SGBD, le support des normes SQL est plus ou moins complet.
    Par conséquent, d'un SGBD à l'autre on aura des syntaxes différentes. En revanche, le serveur, le catalogue et le schéma doivent pouvoir être déduits du contexte de connexion.

    Vérifiez donc la syntaxe de votre chaîne de connexion MySQL, elle doit être incomplète.

    Problème numéro 2 :
    Utilisez des requêtes paramétrées.
    On ne jouit bien que de ce qu’on partage.

  3. #3
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    8 008
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Spécialiste en bases de données
    Secteur : Conseil

    Informations forums :
    Inscription : Septembre 2006
    Messages : 8 008
    Points : 30 947
    Points
    30 947
    Billets dans le blog
    16
    Par défaut
    Bonsoir,



    Selon la documentation officielle, avec MySQL, CREATE DATABASE et CREATE SCHEMA sont synonymes.

    Je ne suis pas spécialiste de MySQL, mais je ne vois pas que l’on puisse faire mention du nom du catalogue dans l’instruction CREATE DATABASE, donc a fortiori dans les instructions telles que CREATE TABLE. A vérifier au près d’un expert MySQL.

    Quoi qu’il en soit, si Temp et Test sont deux bases distinctes, vous pouvez parfaitement coder une instruction du genre de celle-ci, où la table T1 de la base Temp est mise à jour à partir de la table T2 de la base Test :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    INSERT INTO Temp.T1 SELECT * FROM Test.T2 ;    -- mise à jour de la table T1 de la base Temp à partir de la table T2 de la base Test ;

    Au lieu de préfixer les noms des tables, vous pouvez préférer définit la base courante à l’aide de l’instruction USE :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    USE Temp ;
    
    CREATE TABLE T1  (A TEXT NOT NULL) ;
    
    INSERT  INTO T1  VALUES ('Avec les SGBD SQL, il est d''usage de doubler les apostrophes pour les constantes de type caractère') ;
    
    SELECT * FROM T1 ;
    « USE Temp » est en quelque sorte l’homologue MySQL de « SET MaBase = Temp » d’ACCESS.



    Concernant les apostrophes :

    Dans le cas de votre requête, avec les SGBD SQL, il est d’usage de doubler les apostrophes pour les constantes de type caractère :

    'DUPONT' devient ''DUPONT''

    =>

    VALUES ('SELECT * FROM tbl_clients WHERE nom_client=''DUPONT=''')


    Pour plus de sûreté, poser la question dans les forums des SGBD.


    Désolé de ne pas être plus affirmatif....
    (a) Faites simple, mais pas plus simple ! (A. Einstein)
    (b) Certes, E=mc², mais si on discute un peu, on peut l’avoir pour beaucoup moins cher... (G. Lacroix, « Les Euphorismes de Grégoire »)
    => La relativité n'existerait donc que relativement aux relativistes (Jean Eisenstaedt, « Einstein et la relativité générale »)

    __________________________________
    Bases de données relationnelles et normalisation : de la première à la sixième forme normale
    Modéliser les données avec MySQL Workbench
    Je ne réponds pas aux questions techniques par MP. Les forums sont là pour ça.

  4. #4
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 154
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par fsmrel Voir le message
    Concernant les apostrophes :

    Dans le cas de votre requête, avec les SGBD SQL, il est d’usage de doubler les apostrophes pour les constantes de type caractère :

    'DUPONT' devient ''DUPONT''

    =>

    VALUES ('SELECT * FROM tbl_clients WHERE nom_client=''DUPONT=''')


    Pour plus de sûreté, poser la question dans les forums des SGBD.
    Ça, c'est quand on tapes le SQL à la main (tests, etc.)
    Une fois la requête écrite, les variables doivent être gérées sous forme de paramètres.

    En C# par exemple, on aura :
    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    using (SqlConnection cnx = new SqlConnexion(CNX_STRING))
    {
        SqlCommand cmd = cnx.CreateCommand();
        cmd.CommandText = "select * from tbl_clients where nom_client = @nom";
        cmd.Parameters.AddWithValue("nom", "DUPONT");
        cmd.Prepare();
        DataReader dr = cmd.ExecuteReader();
        [...]
    }

    Au détail près du nommage des paramètres, qui n'est pas supporté par tous les SGBD (ou parfois avec des syntaxes différentes, Oracle par exemple prend ":" et non "@" comme préfixe de variable), on peut utiliser des paramètres non nommés : on utilise alors "?" à la place.

    Quels sont les avantages des requêtes paramétrées ?

    1/ Réutilisation du plan d'exécution déjà calculé, avec réduction du nombre de plans en cache, donc l'augmentation des chances pour avoir un plan déjà en mémoire
    En effet, "select * from tbl_clients where nom = 'DUPONT';" et "select * from tbl_clients where nom = 'DURAND';" génèrent deux plans d'exécution distincts dans le cache du SGBD. Ainsi, la partie la plus coûteuse d'une telle requête étant le calcul du plan d'exécution, on perds en performance. Ensuite, le nombre de plans en cache est limité. Donc si par exemple on a 11 noms qu'on recherche à la suite, en boucle, et que le SGBD met en cache les 10 dernières requêtes uniquement, on ne réutilisera jamais de plan déjà calculé. En revanche "select * from tbl_clients where nom_client = @nom;" générera toujours le même plan d'exécution, quelle que soit la valeur du paramètre @nom. Ainsi, 11 nom à chercher = 1 seule requête à compiler. Laissant de la place en mémoire pour d'autres requêtes.

    2/ Blindage des types : si au lien d'utiliser "Parameters.AddWithValue" on utilise juste "Parameters.Add", on doit indiquer explicitement le type, la taille et la précision de la variable. Ainsi, avant de chercher à compiler quoi que ce soit, l'application cliente est capable, au moment du "Prepare()" de déterminer si la requête va compiler ou non : cela évite de coûteux allez-retour sur le réseau et de lancer le compilateur SQL pour rien.

    3/ Blindage des types chaînes de caractère et binaires : si une chaîne de caractère contient un ', en valeur littérale, on risque d'omettre (surtout si un hacker s'amuse à utilise des caractères spéciaux, regexp et autres) de doubler la quote. Ainsi, tout le reste du contenu de la chaîne sera interprété comme du SQL et non comme une variable.
    Exemple :
    L'utilisateur, au lieu de rechercher "DUPONT", recherche "DE L'ESPLANADE"
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    select * from tbl_client where nom = 'DE L'EXPLANADE';
    => Le moteur du SGBD va planter. Ouf.
    Maintenant, un hacker recherche "DTC';DROP DATABASE MABASE;select 'Pleure maintenant petit scarabé"
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    select * from tbl_client where nom = 'DTC';DROP DATABASE MABASE;select 'Pleure maintenant petit scarabé';
    Et là tout se passe bien : le SGBD recherche le client qui s'appelle "DTC". Il trouve rien. Ensuite, il droppe la base de données "MABASE". Et enfin il retourne un message pour te narguer.
    Autre exemple, le formulaire de login qui te log tout le temps :
    Login : "administrateur"
    Pass : "dtc' or 'a' = 'a"
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    select * from tbl_client where login = 'administratreur' and pass = 'dtc' or 'a' = 'a;
    => Hop, le gars se logue en administrateur sans connaître le mot de passe
    Avec une requête paramétrée, aucune de ces injection SQL ne peut fonctionner : la valeur est encapsulée dans une variable SQL, dont il est impossible de déborder (à moins d'une faille du SGBD lui-même ou du pilote ODBC).

    4/ Lisibilité du code
    Quand on commence à avoir beaucoup de chaînes littérales, et que certaines sont des constantes alors que d'autres sont des variables, c'est illisible. Surtout quand la requête est construite de façon dynamique. Utiliser des variables permet de simplifier la relecture de la requête en évitant de construire la chaîne à grand coups de concaténation.

    Donc au final :

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    SELECT INTO table_ordres_SQL VALUES (@query)
    => Et du passe la variable query à la requête au moment de son exécution.
    On ne jouit bien que de ce qu’on partage.

  5. #5
    Expert éminent sénior
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 361
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 361
    Points : 20 386
    Points
    20 386
    Par défaut
    bonjour,
    je vous remercie de vos réponses je vais prendre en compte tout cela.

  6. #6
    Expert éminent sénior
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 361
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 361
    Points : 20 386
    Points
    20 386
    Par défaut
    je relance ce sujet en remerciant pour cette réponse notamment
    Citation Envoyé par fsmrel Voir le message

    Concernant les apostrophes :

    Dans le cas de votre requête, avec les SGBD SQL, il est d’usage de doubler les apostrophes pour les constantes de type caractère :

    'DUPONT' devient ''DUPONT''
    c'est la solution que je vais prendre car SQLBindParameter de l' API ODBC me fait pousse à m'arracher les cheveux de la tête...
    Citation Envoyé par StringBuilder Voir le message
    Problème numéro 2
    Utilisez des requêtes paramétrées.
    c'est ce que j'ai tenté de faire mais comme je viens de l'écrire SQLBindParameter est compliquée à utiliser ; la syntaxe est facile mais par contre il faut gérer les types de données.
    En tout cas merci ça fonctionne avec le doublement des apostrophes.

    encore merci pour les réponses

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

Discussions similaires

  1. [Tableaux] Syntaxe d'echo d'une requête SQL
    Par redvivi dans le forum Langage
    Réponses: 9
    Dernier message: 16/03/2008, 10h48
  2. Erreur de syntaxe dans une requête SQL
    Par Gabout dans le forum Requêtes et SQL.
    Réponses: 11
    Dernier message: 08/01/2008, 17h19
  3. Erreur de syntaxe dans une requête SQL
    Par amnesias dans le forum Langage SQL
    Réponses: 2
    Dernier message: 23/01/2007, 12h50
  4. problème de syntaxe delphi pour une requête sql
    Par socooooool dans le forum Bases de données
    Réponses: 12
    Dernier message: 07/07/2006, 16h53
  5. Nombre Total d'Enregistrements d'une Requête d'Union
    Par sqlnet dans le forum Langage SQL
    Réponses: 5
    Dernier message: 30/12/2003, 17h12

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