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 :

Création de la FAQ SQL !!! (Voulez-vous participer ?)


Sujet :

Langage SQL

  1. #21
    Membre habitué
    Homme Profil pro
    Directeur technique
    Inscrit en
    Mars 2005
    Messages
    251
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2005
    Messages : 251
    Points : 174
    Points
    174
    Par défaut
    Pourquoi pas ! Mais j'aurais vraiment peur de ne pas etre à la hauteur pour ce genre d'articles. Je peux tout de fois essayer d'écreir quelque chose de convenable.

    J'y réfléchis et je te bip lol

  2. #22
    Expert éminent

    Avatar de Maxence HUBICHE
    Homme Profil pro
    Développeur SQLServer/Access
    Inscrit en
    Juin 2002
    Messages
    3 842
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Développeur SQLServer/Access

    Informations forums :
    Inscription : Juin 2002
    Messages : 3 842
    Points : 9 197
    Points
    9 197
    Par défaut
    Citation Envoyé par Tchinkatchuk
    J'y réfléchis et je te bip lol
    Banco !

  3. #23
    Membre du Club
    Inscrit en
    Mai 2005
    Messages
    53
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 53
    Points : 50
    Points
    50
    Par défaut
    Ca peut parraitre tout bete mais c'est pratique des fois :

    : Comment remplacer le count(distinct) dans Access
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SELECT count(*)
    FROM (SELECT DISTINCT Nom_Du_Champ FROM LaTable);
    Ouam'

    Pensez à utiliser lorsque c'est le cas, et pensez au délestage si vos questions ne pourront servir aux autres...

    Pensez à lire la FAQ PHP

  4. #24
    Membre expérimenté Avatar de nebule
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    1 507
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 1 507
    Points : 1 464
    Points
    1 464
    Par défaut
    Petite idée, qui va peut etre semblée bete mais, comment construire une requete "basique" :

    Réponse :

    Select LE_NOM_DU_CHAMPS
    From LE_NOM_DE_LA_TABLE
    Des conditions peuvent être ajoutée avec la clause Where.



    Autre question, les alias. (il me semble pas l'avoir vu).
    Donc, comment utiliser les alias :

    Réponse :
    Select ALIAS.LE_NOM_DU_CHAMP
    From LE_NOM_DE_LA_TABLE ALIAS
    (\ _ /)
    (='.'=)
    (")-(")

  5. #25
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 768
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 768
    Points : 52 565
    Points
    52 565
    Billets dans le blog
    5
    Par défaut
    Excusez moi d'intervenir mais dans 80 % des réponses que vous donnez pour la FAQ SQL, il ne s'agit nullement de SQL !

    TOP, SHRINK, BYTE, SYSDATE, tablespace, TO_CHAR, ADD_MONTHS n'existe pas en SQL

    Le Update avec correlation de table n'est pas codifié comme cela en SQL.

    Bref ce n'est pas un FAQ sur SQL, mais sur du chararbia d'éditeurs et risque de nous pourrir plus la vie que de la solutionner. Les utilisateurs auront l'aire malin quand on leurt dira "oui mais ça sa marche avec la version 6.54656123321512 de BidouilleSQL de L'éditeur MicroBasouille"..

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  6. #26
    Membre expert
    Avatar de LeoAnderson
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 2 938
    Points : 3 199
    Points
    3 199
    Par défaut
    Merci de cette précision, mais aurais-tu une méthode (simple, de préférence) permettant de valider la compatibilité de telle ou telle proposition avec telle ou telle version de la norme ?

  7. #27
    Membre éclairé Avatar de remika
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    806
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 806
    Points : 861
    Points
    861
    Par défaut
    J'ai quelques propositions à faire concernant cette FAQ.

    Déjà il faudrait dans le cas où les réponses sont différentes selon le SGBD lister ces réponses justement, et surtout utiliser beaucoup d'exemples. Typiquement, dans la partie concernant les limites les trois questions sont à peu près équivalentes et les réponses aussi mais pour des SGBD différents. Et à la question
    Comment sélectionner entre le X° et le Y° enregistrement (X<Y) :
    les LIMIT sont une bonne solution quand ils existent... (LIMIT X,Y-X).

    Sinon la partie types de données pourrait commencer par un tableau avec tous les types existants pour les SGBD les plus communs (je crois en avoir vu un dans un des tutoriels).

    sinon une question qui peut être utile :
    Q comment donner un nom "compréhensible" à ma sélection ?
    R en la nommant grâce au mot-clé AS
    Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    SELECT COUNT(*) AS total
    FROM ma_table;
    En espérant vous avoir aidé...
    Ignorer c'est aussi croire que l'on sait.
    Merci d'essayer d'écrire correctement.
    Pas de questions techniques par MP SVP.

  8. #28
    Xo
    Xo est déconnecté
    Expert confirmé
    Avatar de Xo
    Inscrit en
    Janvier 2005
    Messages
    2 701
    Détails du profil
    Informations personnelles :
    Âge : 50

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 701
    Points : 4 238
    Points
    4 238
    Par défaut
    Q réaliser un cumul progressif sur des lignes (qu'il est possible de trier via un champ dédié)
    (cf post de lper du 28/07/2005)

    R
    Soit une table de lignes de factures (Ligne) comportant les champs suivants :
    - idFacture (FK vers une entête),
    - Numero (critère de tri, unique par idFacture),
    - Montant

    Voici la requête (jointures Oracle 8, pas de JOIN )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    SELECT 
      Numero, 
      Montant,
      (SELECT SUM(S.Montant)
         FROM Ligne S
    	WHERE P.idFacture = S.idFacture
    	  AND P.Numero >= S.Numero) AS CUMUL_PARTIEL
    FROM
      Ligne P
    WHERE 
      idFacture = monNumeroDeFacture
    ORDER BY Numero
    La somme partielle est calculée en faisant dans une sous-requête la somme des montants des lignes dont le n° est inférieur ou égal à celui en cours. Les alias sont P pour Principale et S pour secondaire.
    "Ce que l'on conçoit bien s'énonce clairement,
    Et les mots pour le dire arrivent aisément." Nicolas Boileau

    "Expliquer empêche de comprendre si cela dispense de chercher"

    Quiz Oracle : venez tester vos connaissances !

    La FAQ Oracle : 138 réponses à vos questions
    Aidez-nous à la compléter

  9. #29
    Inactif   Avatar de Médiat
    Inscrit en
    Décembre 2003
    Messages
    1 946
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 946
    Points : 2 227
    Points
    2 227
    Par défaut
    Sélection multivaluée

    Question souvent posée :
    J'ai des vendeurs qui travaillent sur plusieurs villes, si j'interroge ma base, j'obtiens :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    1   Paris 
    1   Lille 
    1   Lyon 
    1   Marseille 
    1   Bordeaux 
    2   Paris 
    2   Lyon 
    2   Brest 
    3   Paris
    je voudrais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    3   Paris 
    2   Brest;Lyon;Paris 
    1   Bordeaux;Lille;Lyon;Marseille;Paris
    Cette question est souvent rejeté au rang de cosmétique, personnellement, j'ai tendance à penser (hors tous problèmes de performance) qu'il s'agit d'une fonction agrégative au même titre que SUM ou AVG (mais avec des problèmes spécifiques de taille, d'ordre, etc...).

    Voici une solution avec le WITH RECURSIVE de la norme SQL 3 (ou SQL1999) (en fait il n'y a pas le "RECURSIVE", puisque SQLExpress 2005 supporte la fonction, mais pas le mot clé )


    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
    create table Territoire (IdVendeur integer, Ville varchar(20)) 
     
    insert into Territoire values (1, 'Paris'); 
    insert into Territoire values (1, 'Lille'); 
    insert into Territoire values (1, 'Lyon'); 
    insert into Territoire values (1, 'Marseille'); 
    insert into Territoire values (1, 'Bordeaux'); 
    insert into Territoire values (2, 'Paris'); 
    insert into Territoire values (2, 'Lyon'); 
    insert into Territoire values (2, 'Brest'); 
    insert into Territoire values (3, 'Paris'); 
     
     
     
    with px (idVendeur, Villes, Precedente, Niveau) as 
         (   select IdVendeur, cast(Ville as varchar(MAX)), cast (ville as varchar(MAX)), 1 
             from   Territoire a 
             where  Ville = (select min(Ville) from Territoire b where a.idVendeur = b.idVendeur) 
          union all 
             select a.IdVendeur, px.Villes + ';' + a.ville, cast(a.Ville as varchar(max)), Niveau + 1 
             from Territoire a inner join px on a.idVendeur = px.idVendeur and a.Ville > px.Precedente 
         ) 
    select IdVendeur, Villes 
    from px a 
    where Niveau = (select max(Niveau) from px b where a.idVendeur = b.idVendeur)
    Attention, cette solution est sans doute assez mauvaise en terme de performance si le nombre de "Villes" est élevé.

    Avec les mêmes données (et les mêmes risque au niveau des performances) que pour la première solution, voici un exemple pour ORACLE :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    SELECT idVendeur, Liste 
    FROM (SELECT idVendeur, Ville, PRIOR Ville, LEVEL AS niveau, sys_connect_by_path(Ville, ',') AS Liste 
          FROM Territoire a 
          CONNECT BY idVendeur = PRIOR idVendeur AND Ville > PRIOR Ville 
          START WITH (idVendeur, Ville) IN (SELECT idVendeur, Min(Ville) FROM Territoire GROUP BY idVendeur) 
         ) b 
    WHERE niveau = (SELECT Max(Niveau) 
                    FROM (SELECT idVendeur, Ville, PRIOR Ville, LEVEL AS niveau, sys_connect_by_path(Ville, ',') AS Liste 
                          FROM Territoire a 
                          CONNECT BY idVendeur = PRIOR idVendeur AND Ville > PRIOR Ville 
                          START WITH (idVendeur, Ville) IN (SELECT idVendeur, Min(Ville) FROM Territoire GROUP BY idVendeur) 
                         ) a 
                    WHERE a.idVendeur = b.idVendeur 
                   );
    sys_connect_by_path est "officiel" depuis la 9i, mais fonctionne depuis la 8i (undocumented, donc à éviter dans un environnement de production )

    On voit bien l'intérêt du WITH sur cet exemple


    Amélioration de la solution ORACLE (grâce à une idée de FRED_D dans ce post : http://www.developpez.net/forums/sho...d.php?t=157487) qui simplifie énormément le PLAN en remplaçant une sous requête compliquée par une fonction analytique pour calculer un MAX ( )...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     SELECT idVendeur, LTRIM(Liste, '; ')
     FROM (SELECT idVendeur, Ville, Liste, Niveau, MAX(niveau) OVER (PARTITION BY idVendeur) max_niv
           FROM (SELECT idVendeur, Ville, PRIOR Ville, LEVEL AS niveau, sys_connect_by_path(Ville, '; ') AS Liste 
                 FROM Territoire a 
                 CONNECT BY idVendeur = PRIOR idVendeur AND Ville > PRIOR Ville 
                 START WITH (idVendeur, Ville) IN (SELECT idVendeur, Min(Ville) FROM Territoire GROUP BY idVendeur)))
    WHERE niveau = max_niv;
    Le LTRIM sur la liste permet de retirer le séparateur en début de liste.
    J'affirme péremptoirement que toute affirmation péremptoire est fausse
    5ième élément : barde-prince des figures de style, duc de la synecdoque
    Je ne réponds jamais aux questions techniques par MP

  10. #30
    Xo
    Xo est déconnecté
    Expert confirmé
    Avatar de Xo
    Inscrit en
    Janvier 2005
    Messages
    2 701
    Détails du profil
    Informations personnelles :
    Âge : 50

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 701
    Points : 4 238
    Points
    4 238
    Par défaut
    • Q : Dans une table d'événements datés, comment récupérer l'enregistrement le plus récent ?
    • R : Via une sous-requête, grâce à l'opérateur MAX.


    Voici un jeu d'essai illustrant 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
    CREATE TABLE Evenement (
    eveCle NUMBER(10),  -- clé
    evedat DATE,        -- date de l'événement
    eveCat NUMBER(10),  -- catégorie de l'événement
    eveCmt VARCHAR2(32) -- commentaire
    );
     
    INSERT INTO Evenement (eveCle, eveDat, eveCat, eveCmt)
                   VALUES (1, CAST('25/12/2005' AS DATE), 1, 'Démarrage des festivités');
    INSERT INTO Evenement (eveCle, eveDat, eveCat, eveCmt)
                   VALUES (2, CAST('27/12/2005' AS DATE), 2, 'Petite pause ...');
    INSERT INTO Evenement (eveCle, eveDat, eveCat, eveCmt)
                   VALUES (3, CAST('31/12/2005' AS DATE), 1, 'Et on remet ça !');
    INSERT INTO Evenement (eveCle, eveDat, eveCat, eveCmt)
                   VALUES (4, CAST('02/01/2006' AS DATE), 2, 'Réveil ... :?');
     
    COMMIT;
    La requête suivante nous permet d'obtenir que l'événement le plus récent :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SQL> SELECT eveDat, eveCmt
      2    FROM Evenement
      3   WHERE eveDat = (SELECT MAX(eveDat)
      4                     FROM Evenement);
     
    EVEDAT   EVECMT
    -------- --------------------------------
    02/01/06 Réveil ... :?
    Plus finement, si on désire filtrer sur des données précises : il faut alors construire la clause de la requête principale, et la dupliquer dans la sous-requête. De même si une jointure avec une autre table est nécessaire, il faudra la dupliquer ...
    Si dans notre exemple nous souhaitons travailler uniquement sur les événements de catégorie n° 1 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    SQL> SELECT eveDat, eveCmt
      2    FROM Evenement
      3   WHERE eveDat = (SELECT MAX(eveDat)
      4                     FROM Evenement
      5                    WHERE eveCat = 1)
      6     AND eveCat = 1;
     
    EVEDAT   EVECMT
    -------- --------------------------------
    31/12/05 Et on remet ça !
    Remarques :
    • Si l'unicité n'est pas assurée pour le champ servant à effectuer le tri (ici, eveDat), alors la requête sera susceptible de retourner plusieurs enregistrements de même rang si les doublons se situent sur la date la plus récente.
    • Si votre SGBD ne vous permet pas les sous-requête (ex : MySQL 4.0 ou antérieur), alors une solution de rechange est la suivante : faite un tri (ORDER BY eveDat DESC) et débrouillez-vous pour récupérer seulement la première ligne (TOP 1)


    Bon, ce point était déjà abordé dans la première page de ce topic, j'espère juste que le complément en valait la peine
    "Ce que l'on conçoit bien s'énonce clairement,
    Et les mots pour le dire arrivent aisément." Nicolas Boileau

    "Expliquer empêche de comprendre si cela dispense de chercher"

    Quiz Oracle : venez tester vos connaissances !

    La FAQ Oracle : 138 réponses à vos questions
    Aidez-nous à la compléter

  11. #31
    Xo
    Xo est déconnecté
    Expert confirmé
    Avatar de Xo
    Inscrit en
    Janvier 2005
    Messages
    2 701
    Détails du profil
    Informations personnelles :
    Âge : 50

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 701
    Points : 4 238
    Points
    4 238
    Par défaut
    • Q : Comment personnaliser un tri ?
    • R : Via plusieurs requêtes distinctes dans lesquelles les données sont filtrées, requêtes qui sont ensuite regroupées grâce à des UNION et un pseudo-champ permettant de définir un critère de tri prépondérant. On renommera ce champ grâce à un alias (AS)


    Voici un jeu d'essai avec une table de contacts toute simple, que l'on souhaite trier par codes postaux, dans un ordre personnalisé :

    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
    CREATE TABLE Contact (
    Cle NUMBER(10),   -- clé
    Nom VARCHAR2(32), -- nom
    Cpo VARCHAR2(5)   -- code postal
    );
     
    INSERT INTO Contact (Cle, Nom, Cpo)
                 VALUES (1, 'Philippe', '14200');
    INSERT INTO Contact (Cle, Nom, Cpo)
                 VALUES (2, 'Laurent', '75001');
    INSERT INTO Contact (Cle, Nom, Cpo)
                 VALUES (3, 'Arthur', '14610');
    INSERT INTO Contact (Cle, Nom, Cpo)
                 VALUES (4, 'Joseph', '42000');
    INSERT INTO Contact (Cle, Nom, Cpo)
                 VALUES (5, 'Céline', '14000');
    INSERT INTO Contact (Cle, Nom, Cpo)
                 VALUES (6, 'Jean-Jacques', '75003');
     
    COMMIT;
    Je souhaite obtenir la liste de mes contacts, en triant de la manière suivante :
    • d'abord ceux dans le Calvados (14),
    • ensuite ceux sur Paris (75),
    • et pour finir les autres


    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
    SELECT 1 AS MonTri, Nom, Cpo
      FROM Contact
     WHERE Cpo LIKE '14%'
    UNION
    SELECT 2 AS MonTri, Nom, Cpo
      FROM Contact
     WHERE Cpo LIKE '75%'
    UNION
    SELECT 3 AS MonTri, Nom, Cpo
      FROM Contact
     WHERE Cpo NOT LIKE '75%'
       AND Cpo NOT LIKE '14%'
    ORDER BY MonTri, Cpo;
     
        MONTRI NOM                              CPO
    ---------- -------------------------------- -----
             1 Céline                           14000
             1 Philippe                         14200
             1 Arthur                           14610
             2 Laurent                          75001
             2 Jean-Jacques                     75003
             3 Joseph                           42000
    Remarques :
    "Ce que l'on conçoit bien s'énonce clairement,
    Et les mots pour le dire arrivent aisément." Nicolas Boileau

    "Expliquer empêche de comprendre si cela dispense de chercher"

    Quiz Oracle : venez tester vos connaissances !

    La FAQ Oracle : 138 réponses à vos questions
    Aidez-nous à la compléter

  12. #32
    Inactif   Avatar de Médiat
    Inscrit en
    Décembre 2003
    Messages
    1 946
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 946
    Points : 2 227
    Points
    2 227
    Par défaut
    A propos du tri personnalisé :

    Remarque : l'exemple donné ne gère pas le cas où Cpo est NULL, il faut rajouter OR Cpo IS NULL dans le dernier WHERE.

    Si le moteur autorise le CASE WHEN, je trouve la solution suivante plus élégante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT Nom, Cpo
    FROM Contact
    ORDER BY CASE WHEN Cpo LIKE '14%'
                  THEN 1
                  WHEN Cpo LIKE '75%'
                  THEN 2
                  ELSE 3
             END, Cpo
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    NOM          CPO  
    Céline       14000
    Philippe     14200
    Arthur       14610
    Laurent      75001
    Jean-Jacques 75003
    Joseph       42000
    J'affirme péremptoirement que toute affirmation péremptoire est fausse
    5ième élément : barde-prince des figures de style, duc de la synecdoque
    Je ne réponds jamais aux questions techniques par MP

  13. #33
    Xo
    Xo est déconnecté
    Expert confirmé
    Avatar de Xo
    Inscrit en
    Janvier 2005
    Messages
    2 701
    Détails du profil
    Informations personnelles :
    Âge : 50

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 701
    Points : 4 238
    Points
    4 238
    Par défaut
    • Q : Dans une relation parent-enfant, lister les parents en comptant leur nombre d'enfants... et sans oublier les parent sans enfants !
    • R : Via un COUNT classique, et une jointure externe


    Voici un jeu d'essai avec une table Parent et une table Enfant :

    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
    -- création d'une table Parent :
    CREATE TABLE Parent (
    idParent NUMBER(10),
    LbParent VARCHAR2(32));
     
    -- création d'une table Enfant :
    CREATE TABLE Enfant (
    idEnfant NUMBER(10),
    idParent NUMBER(10),
    LbEnfant VARCHAR2(32));
     
    --Insertion de 2 enregistrements dans Parent :
    INSERT INTO Parent VALUES (1, 'Toto');
    INSERT INTO Parent VALUES (2, 'Tutu');
     
    --Insertion de 2 Fils, sur le premier Parent :
    INSERT INTO Enfant VALUES (1, 1, 'premier fils de Toto');
    INSERT INTO Enfant VALUES (2, 1, 'second fils de Toto');
    -- ... donc le second parent a 0 enfant !
     
    COMMIT;
    Une requête classique pour compter le nombre d'enfants nous ramène uniquement les parents avec enfant(s) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT P.idParent, COUNT(idEnfant) AS Nombre
      FROM Parent P INNER JOIN Enfant E ON P.idParent = E.idParent
     GROUP BY P.idParent;
     
      IDPARENT NOMBRE
    ---------- -------------
             1             2
    Mais en implémentant une jointure externe, on a bien tout le monde :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT P.idParent, COUNT(idEnfant) AS Nombre
      FROM Parent P LEFT OUTER JOIN Enfant E ON P.idParent = E.idParent
     GROUP BY P.idParent;
     
      IDPARENT NOMBRE
    ---------- -------------
             1             2
             2             0
    "Ce que l'on conçoit bien s'énonce clairement,
    Et les mots pour le dire arrivent aisément." Nicolas Boileau

    "Expliquer empêche de comprendre si cela dispense de chercher"

    Quiz Oracle : venez tester vos connaissances !

    La FAQ Oracle : 138 réponses à vos questions
    Aidez-nous à la compléter

  14. #34
    Membre extrêmement actif Avatar de cortex024
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    1 301
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2005
    Messages : 1 301
    Points : 1 119
    Points
    1 119
    Par défaut
    Q: Comment calculez un âge à partir d'un champ DATETIME?
    R:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    YEAR(FROM_DAYS(1 + TO_DAYS(CURDATE()) - TO_DAYS(birthday))) as age
    où birthday contient une date de naissance.

  15. #35
    Inactif   Avatar de Médiat
    Inscrit en
    Décembre 2003
    Messages
    1 946
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 946
    Points : 2 227
    Points
    2 227
    Par défaut [SQL3]Calcul du PUMP (cas d'école)
    Le calcul du PUMP (Prix Unitaire Moyen Pondéré) est un sujet courant et il existe plusieurs façon de valoriser un stock, le but de l'exemple ci-dessous n’est pas de faire un cours de gestion de stock, mais de donner un exemple d’utilisation de la récursion avec SQL.
    Une seule table est nécessaire, elle est ici baptisée REC_STOCK et permet d’enregistrer les mouvements (entrée et sortie) du stock, le pré-requis pour que la requête qui permet de calculer le PUMP fonctionne est que les mouvements aient lieu dans l’ordre (seules des sorties de quantités disponibles sont autorisées).
    Création de la table (sans l’intégrité référentielle pour m’éviter de créer la table Produit par exemple)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Create table REC_STOCK (IdProduit integer, DateMvt datetime, Quantite integer, PU float);
    Insertion de données :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    insert into rec_stock (IdProduit, DateMvt, Quantite, PU) Values (1, '2006-01-01 00:00:00', 10, 10);
    insert into rec_stock (IdProduit, DateMvt, Quantite, PU) Values (1, '2006-01-02 00:00:00', -5, null);
    insert into rec_stock (IdProduit, DateMvt, Quantite, PU) Values (1, '2006-01-05 00:00:00', 10, 20);
    insert into rec_stock (IdProduit, DateMvt, Quantite, PU) Values (1, '2006-01-10 00:00:00', 10, 15);
    insert into rec_stock (IdProduit, DateMvt, Quantite, PU) Values (1, '2006-01-20 00:00:00', -10, null);
    insert into rec_stock (IdProduit, DateMvt, Quantite, PU) Values (1, '2006-01-26 00:00:00', 20, 12);
    insert into rec_stock (IdProduit, DateMvt, Quantite, PU) Values (1, '2006-02-10 00:00:00', -35, null);
    insert into rec_stock (IdProduit, DateMvt, Quantite, PU) Values (1, '2006-02-12 00:00:00', 50, 5);
    insert into rec_stock (IdProduit, DateMvt, Quantite, PU) Values (1, '2006-02-20 00:00:00', 10, 10);
    (les mouvements sont tous à des dates différentes (plus facile à saisir), mais, bien sur, cela marche tout aussi bien avec des mouvements ayant lieu le même jour, tant que c’est à des heures différentes).
    On voit dans l’exemple ci-dessus que le PU est à null pour les sorties.
    Principe du calcul (pour un article donné) :
    Lors d’une entrée la valeur du stock est égal à la valeur précédente (0 si c’est le premier achat) + le prix d’achat * Quantité. Le PUMP est alors égal à la nouvelle valeur du stock divisé par la nouvelle quantité en stock.
    Lors d’une sortie la valeur du stock est égal à la valeur précédente – le PUMP précédent * Quantité (ne peut être négatif). Le PUMP n’est pas modifié.
    Voici la requête qui permet de calculer le PUMP
    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
    WITH PUMP (IdProduit, DateMvt, Ordre, Quantite, PU, Cout, Stock, PUMP, Valeur) AS
        (SELECT IdProduit, DateMvt, 1 as Ordre, Quantite, PU, cast (Quantite * PU as float) as Cout,
                Quantite as Stock, PU as PUMP, Quantite * PU as Valeur
         FROM REC_Stock r
         WHERE NOT EXISTS (SELECT NULL
                           FROM REC_STOCK s
                           WHERE r.IdProduit = s.IdProduit
                             AND s.DateMvt < r.DateMvt)
        union all
         SELECT r.IdProduit, r.DateMvt, p.Ordre + 1, r.Quantite, r.PU,
                case when r.Quantite < 0 then r.Quantite * p.PUMP
                     else r.Quantite * r.PU
                     end,
                r.Quantite + p.Stock,
                case when r.Quantite < 0 and r.Quantite + p.Stock > 0 then p.PUMP
                     when r.Quantite + p.Stock = 0 then NULL
                     else (p.Valeur + r.Quantite * r.PU) / (p.Stock + r.Quantite)
                     end,
                p.Valeur + case when r.Quantite > 0 then r.Quantite * r.PU
                                else r.Quantite * p.PUMP
                                end
         FROM PUMP p inner join REC_Stock r
                           on  p.IdProduit = r.IdProduit
                           and r.DateMvt > p.DateMvt
                           and NOT EXISTS (select NULL
                                           FROM REC_STOCK s
                                           WHERE r.IdProduit = s.IdProduit
                                           AND s.DateMvt > p.DateMvt
                                           AND s.DateMvt < r.DateMvt)
        )
    select * from PUMP order by IdProduit, Ordre;
    et le résultat :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    IdProduit DateMvt                   Ordre  Quantite  PU     Cout  Stock  PUMP   Valeur
    1         2006-01-01 00:00:00.000   1      10        10     100   10     10     100
    1         2006-01-02 00:00:00.000   2      -5        NULL   -50    5     10      50
    1         2006-01-05 00:00:00.000   3      10        20     200   15     16,67  250
    1         2006-01-10 00:00:00.000   4      10        15     150   25     16     400
    1         2006-01-20 00:00:00.000   5     -10        NULL  -160   15     16     240
    1         2006-01-26 00:00:00.000   6      20        12     240   35     13,71  480
    1         2006-02-10 00:00:00.000   7     -35        NULL  -480    0     NULL     0
    1         2006-02-12 00:00:00.000   8      50         5     250   50      5     250
    1         2006-02-20 00:00:00.000   9      10        10     100   60      5,83  350
    J'affirme péremptoirement que toute affirmation péremptoire est fausse
    5ième élément : barde-prince des figures de style, duc de la synecdoque
    Je ne réponds jamais aux questions techniques par MP

  16. #36
    Xo
    Xo est déconnecté
    Expert confirmé
    Avatar de Xo
    Inscrit en
    Janvier 2005
    Messages
    2 701
    Détails du profil
    Informations personnelles :
    Âge : 50

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 701
    Points : 4 238
    Points
    4 238
    Par défaut
    • Q : Comment faire appel plusieurs fois à la même table dans une seule requête ?
    • R : Grâce aux alias !
    Voici un jeu d'essai fréquement rencontré, de type "championnat" illustrant ceci :
    La table Match permet de fixer la date du match, le club recevant (Match_Locaux) et le club se déplaçant (Match_Visiteur). Les contraintes d'intégrités ne sont pas gérées dans l'exemple afin de ne pas alourdir les scripts.

    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
    CREATE TABLE Club (
    Club_Id NUMBER (10), 
    Club_Nom VARCHAR2 (32));
     
    CREATE TABLE Match (
    Match_Date DATE,
    Match_Locaux NUMBER (10), 
    Match_Visiteur NUMBER (10));
     
    INSERT INTO Club VALUES (1, 'Auxerre');
    INSERT INTO Club VALUES (2, 'Bordeaux');
    INSERT INTO Club VALUES (3, 'Le Mans');
    INSERT INTO Club VALUES (4, 'Lens');
    ...
     
    INSERT INTO Match VALUES (CAST ('03/12/2006' AS DATE), 1, 3);
    INSERT INTO Match VALUES (CAST ('03/12/2006' AS DATE), 4, 2);
    ...
     
    COMMIT;
    La requête suivante nous permet d'obtenir les matches du 03 décembre 2006 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    SQL> SELECT LOC.Club_Nom AS Locaux, VIS.Club_Nom AS Visiteurs
      2    FROM Match INNER JOIN Club LOC ON Match_Locaux = LOC.Club_Id
      3               INNER JOIN Club VIS On Match_Visiteur = VIS.Club_Id
      4   WHERE Match_Date = CAST ('03/12/2006' AS DATE);
     
    LOCAUX                           VISITEURS
    -------------------------------- --------------------------------
    Auxerre                          Le Mans
    Lens                             Bordeaux
    Remarques :
    • Si la syntaxe de CAST ne fonctionne pas sur votre SGBD, susbstituez-lui la fonction de transtypage ad hoc (TO_DATE, ...)
    • Les alias sur les noms de champs sont utiles afin de différencier les champs retournés par la requête.
    "Ce que l'on conçoit bien s'énonce clairement,
    Et les mots pour le dire arrivent aisément." Nicolas Boileau

    "Expliquer empêche de comprendre si cela dispense de chercher"

    Quiz Oracle : venez tester vos connaissances !

    La FAQ Oracle : 138 réponses à vos questions
    Aidez-nous à la compléter

  17. #37
    Xo
    Xo est déconnecté
    Expert confirmé
    Avatar de Xo
    Inscrit en
    Janvier 2005
    Messages
    2 701
    Détails du profil
    Informations personnelles :
    Âge : 50

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 701
    Points : 4 238
    Points
    4 238
    Par défaut
    Question : Doit-on faire les jointures dans la clause WHERE ou avec des JOIN ?
    Réponse :

    Citation Envoyé par SQLPro
    Il peut paraître étonnant que les requêtes avec les jointures dans la clause WHERE demeurent assez fréquentes, alors que la norme SQL2 (qui date de 1992) préconise l'emploi de JOIN (cf Les jointures, ou comment interroger plusieurs tables).

    D'après l'article cité précédement, la réponse est donc la suivante : il est préférable de vous conformer à la norme, pour les raisons suivantes :
    • Les jointures faites dans la clause WHERE (ancienne syntaxe de 1986 !) ne permettent pas de faire la distinction de prime abord entre ce qui relève du filtrage et ce qui relève de la jointure.
    • Il est à priori absurde de vouloir filtrer dans le WHERE (ce qui restreint les données du résultat) et de vouloir "élargir" ce résultat par une jointure dans la même clause WHERE de filtrage.
    • La lisibilité des requêtes est plus grande en utilisant la syntaxe à base de JOIN, en isolant ce qui est du filtrage et de la jointure, mais aussi en isolant avec clarté chaque condition de jointures entre chaque couples de table.
    • L'optimisation d'exécution de la requête est souvent plus pointue du fait de l'utilisation du JOIN.
    • Lorsque l'on utilise l'ancienne syntaxe et que l'on supprime la clause WHERE a des fins de tests, le moteur SQL réalise le produit cartésiens des tables ce qui revient la plupart du temps à mettre à genoux le serveur !
    On pourrait rajouter à la liste d'autres bonnes raisons, comme
    - une meilleurs portabilité de vos applications (multi-SGBD),
    - une meilleurs culture générale,

    Et si pour des raisons d'historiques (clients en production avec des versions n'acceptant pas cette syntaxe) vous ne pouvez pas vous conformez à cette norme pour vos développements, cela ne vous empêche pas de la connaître
    "Ce que l'on conçoit bien s'énonce clairement,
    Et les mots pour le dire arrivent aisément." Nicolas Boileau

    "Expliquer empêche de comprendre si cela dispense de chercher"

    Quiz Oracle : venez tester vos connaissances !

    La FAQ Oracle : 138 réponses à vos questions
    Aidez-nous à la compléter

  18. #38
    Membre averti
    Avatar de mboubidi
    Homme Profil pro
    DBA Oracle
    Inscrit en
    Novembre 2006
    Messages
    326
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Algérie

    Informations professionnelles :
    Activité : DBA Oracle
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Novembre 2006
    Messages : 326
    Points : 401
    Points
    401
    Par défaut mboubidi
    Cher Tous,
    Veuillez trouver ci-joint les FRM (FRM-11400 au FRM-41102) avec :
    Définition
    Cause
    Action
    Niveau
    Type
    Salutations.
    Fichiers attachés Fichiers attachés
    Ce que tu veux me dire, est-ce vrai? Est-ce bien? Est-ce utile? Sinon je ne veux pas l'entendre.

    Pensez a

  19. #39
    Rédacteur/Modérateur

    Avatar de Fabien Celaia
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Octobre 2002
    Messages
    4 222
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Suisse

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Service public

    Informations forums :
    Inscription : Octobre 2002
    Messages : 4 222
    Points : 19 551
    Points
    19 551
    Billets dans le blog
    25
    Par défaut
    Je pense que vous vous mettez le pied dans un bourbier si vous acceptez tout ce qui n'est pas pur sucre SQL (soit donc normé). TOP, DATETIME et consors...

    Vous avez djà commencé à sélectionner des syntaxe propres à des moteurs en particuliers, me semble-t-il. Pour cela, il y a les Faq spécifiques...
    Sr DBA Oracle / MS-SQL / MySQL / Postgresql / SAP-Sybase / Informix / DB2

    N'oublie pas de consulter mes articles, mon blog, les cours et les FAQ SGBD

    Attention : pas de réponse technique par MP : pensez aux autres, passez par les forums !

  20. #40
    Membre habitué
    Homme Profil pro
    Data Ingenieur
    Inscrit en
    Mai 2006
    Messages
    133
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Data Ingenieur
    Secteur : Finance

    Informations forums :
    Inscription : Mai 2006
    Messages : 133
    Points : 162
    Points
    162
    Par défaut
    Quand tu parle d'aide c'est genre les triggers,order by,group By jointure naturel ect...?

Discussions similaires

  1. Recherche 1 responsable + des contributeurs pour FAQ SQL
    Par trotters213 dans le forum Evolutions du club
    Réponses: 21
    Dernier message: 20/04/2006, 17h10
  2. Comment voulez vous diviser le forum dotnet (part2)
    Par neo.51 dans le forum Evolutions du club
    Réponses: 28
    Dernier message: 15/04/2005, 10h10

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