Publicité
+ Répondre à la discussion Actualité déjà publiée
Page 2 sur 3 PremièrePremière 123 DernièreDernière
Affichage des résultats 21 à 40 sur 48
  1. #21
    Membre habitué
    Homme Profil pro Sylvain Gourvil
    Directeur technique
    Inscrit en
    mars 2005
    Messages
    251
    Détails du profil
    Informations personnelles :
    Nom : Homme Sylvain Gourvil
    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 : 137
    Points
    137

    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
    Rédacteur

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

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

    Informations forums :
    Inscription : juin 2002
    Messages : 3 843
    Points : 8 237
    Points
    8 237

    Par défaut

    Citation Envoyé par Tchinkatchuk
    J'y réfléchis et je te bip lol
    Banco !

  3. #23
    Nouveau Membre du Club
    Inscrit en
    mai 2005
    Messages
    53
    Détails du profil
    Informations forums :
    Inscription : mai 2005
    Messages : 53
    Points : 25
    Points
    25

    Par défaut

    Ca peut parraitre tout bete mais c'est pratique des fois :

    : Comment remplacer le count(distinct) dans Access
    Code :
    1
    2
    SELECT count(*)
    FROM (SELECT DISTINCT Nom_Du_Champ FROM LaTable);

  4. #24
    Membre Expert Avatar de nebule
    Inscrit en
    octobre 2004
    Messages
    1 507
    Détails du profil
    Informations personnelles :
    Âge : 30

    Informations forums :
    Inscription : octobre 2004
    Messages : 1 507
    Points : 1 302
    Points
    1 302

    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 Frédéric BROUARD
    Expert SGBDR & SQL
    Inscrit en
    mai 2002
    Messages
    13 421
    Détails du profil
    Informations personnelles :
    Nom : Homme Frédéric BROUARD
    Localisation : France

    Informations professionnelles :
    Activité : Expert SGBDR & SQL
    Secteur : Conseil

    Informations forums :
    Inscription : mai 2002
    Messages : 13 421
    Points : 27 585
    Points
    27 585

    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
    Site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Blog SQL, SQL Server, modélisation données : http://blog.developpez.com/sqlpro
    http://www.sqlspot.com : modélisation, conseils, audit, optimisation, formation
    * * * * * Enseignant CNAM PACA - ISEN Toulon - CESI Aix en Provence * * * * *

  6. #26
    Expert Confirmé Avatar de LeoAnderson
    Inscrit en
    septembre 2004
    Messages
    2 940
    Détails du profil
    Informations forums :
    Inscription : septembre 2004
    Messages : 2 940
    Points : 3 030
    Points
    3 030

    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 chevronné Avatar de remika
    Inscrit en
    septembre 2004
    Messages
    806
    Détails du profil
    Informations personnelles :
    Âge : 30

    Informations forums :
    Inscription : septembre 2004
    Messages : 806
    Points : 745
    Points
    745

    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 :
    1
    2
    3
     
    SELECT COUNT(*) AS total
    FROM ma_table;
    En espérant vous avoir aidé...

  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 : 41

    Informations forums :
    Inscription : janvier 2005
    Messages : 2 701
    Points : 3 854
    Points
    3 854

    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 :
    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 : 1 938
    Points
    1 938

    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 :
    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 :
    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 :
    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 :
    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 :
    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.

  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 : 41

    Informations forums :
    Inscription : janvier 2005
    Messages : 2 701
    Points : 3 854
    Points
    3 854

    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 :
    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 :
    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 :
    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 : 41

    Informations forums :
    Inscription : janvier 2005
    Messages : 2 701
    Points : 3 854
    Points
    3 854

    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 :
    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 :
    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 : 1 938
    Points
    1 938

    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 :
    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 :
    1
    2
    3
    4
    5
    6
    7
    NOM          CPO  
    Céline       14000
    Philippe     14200
    Arthur       14610
    Laurent      75001
    Jean-Jacques 75003
    Joseph       42000

  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 : 41

    Informations forums :
    Inscription : janvier 2005
    Messages : 2 701
    Points : 3 854
    Points
    3 854

    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 :
    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 :
    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 :
    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
    Inscrit en
    avril 2005
    Messages
    1 300
    Détails du profil
    Informations forums :
    Inscription : avril 2005
    Messages : 1 300
    Points : 887
    Points
    887

    Par défaut

    Q: Comment calculez un âge à partir d'un champ DATETIME?
    R:
    Code :
    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 : 1 938
    Points
    1 938

    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 :
    CREATE TABLE REC_STOCK (IdProduit integer, DateMvt datetime, Quantite integer, PU float);
    Insertion de données :
    Code :
    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 :
    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 :
    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

  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 : 41

    Informations forums :
    Inscription : janvier 2005
    Messages : 2 701
    Points : 3 854
    Points
    3 854

    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 :
    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 :
    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 : 41

    Informations forums :
    Inscription : janvier 2005
    Messages : 2 701
    Points : 3 854
    Points
    3 854

    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 éclairé
    Avatar de mboubidi
    Homme Profil pro
    DBA Oracle
    Inscrit en
    novembre 2006
    Messages
    306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    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 : 306
    Points : 315
    Points
    315

    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

  19. #39
    Rédacteur/Modérateur
    Avatar de fadace
    Homme Profil pro Fabien Celaia
    Administrateur de base de données
    Inscrit en
    octobre 2002
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Nom : Homme Fabien Celaia
    Âge : 44
    Localisation : Suisse

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

    Informations forums :
    Inscription : octobre 2002
    Messages : 3 932
    Points : 14 813
    Points
    14 813

    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 / Sybase / MS-SQL / MySQL / DB2 / Postgresql / Informix
    Administrateur SAP
    Mes articles

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

  20. #40
    Membre habitué
    Homme Profil pro Gaëtan
    Développeur Oracle
    Inscrit en
    mai 2006
    Messages
    126
    Détails du profil
    Informations personnelles :
    Nom : Homme Gaëtan
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Oracle
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mai 2006
    Messages : 126
    Points : 120
    Points
    120

    Par défaut

    Quand tu parle d'aide c'est genre les triggers,order by,group By jointure naturel ect...?

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •