Précédent   Forum du club des développeurs et IT Pro > Bases de données > Langage SQL
Langage SQL Forum d'entraide sur le langage SQL et sur les questions liées à la conception de schéma (DDL). Cours SQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Actualité déjà publiée
 
Outils de la discussion
Publicité
'
Vieux 17/05/2005, 09h36   #21
Tchinkatchuk
Membre habitué
 
Avatar de Tchinkatchuk
 
Homme Sylvain Gourvil
Freelance en développement Web
Inscription : mars 2005
Messages : 248
Détails du profil
Informations personnelles :
Nom : Homme Sylvain Gourvil
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Freelance en développement Web
Secteur : High Tech - Multimédia et Internet

Informations forums :
Inscription : mars 2005
Messages : 248
Points : 147
Points : 147
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
Tchinkatchuk est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/05/2005, 13h51   #22
Maxence HUBICHE
Rédacteur

 
Avatar de Maxence HUBICHE
 
Homme Maxence HUBICHE
Développeur SQLServer/Access
Inscription : juin 2002
Messages : 3 771
Détails du profil
Informations personnelles :
Nom : Homme Maxence HUBICHE
Âge : 43
Localisation : France, Val d'Oise (Île de France)

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

Informations forums :
Inscription : juin 2002
Messages : 3 771
Points : 8 784
Points : 8 784
Envoyer un message via MSN à Maxence HUBICHE Envoyer un message via Skype™ à Maxence HUBICHE
Citation:
Envoyé par Tchinkatchuk
J'y réfléchis et je te bip lol
Banco !
__________________
Mes tutoriels et vidéos :
Tableaux croisés dynamiques, Access les Bases, et les autres !
Maxence HUBICHE est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/05/2005, 10h53   #23
ouam81
Nouveau Membre du Club
 
Inscription : mai 2005
Messages : 53
Détails du profil
Informations forums :
Inscription : mai 2005
Messages : 53
Points : 25
Points : 25
Envoyer un message via MSN à ouam81
Ca peut parraitre tout bete mais c'est pratique des fois :

Citation:
: Comment remplacer le count(distinct) dans Access
Code :
1
2
SELECT count(*)
FROM (SELECT DISTINCT Nom_Du_Champ FROM LaTable);
ouam81 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/05/2005, 10h58   #24
nebule
Membre Expert
 
Avatar de nebule
 
Inscription : octobre 2004
Messages : 1 508
Détails du profil
Informations personnelles :
Âge : 29

Informations forums :
Inscription : octobre 2004
Messages : 1 508
Points : 1 339
Points : 1 339
Petite idée, qui va peut etre semblée bete mais, comment construire une requete "basique" :

Réponse :

Citation:
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 :
Citation:
Select ALIAS.LE_NOM_DU_CHAMP
From LE_NOM_DE_LA_TABLE ALIAS
nebule est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/05/2005, 14h11   #25
SQLpro
Rédacteur

 
Avatar de SQLpro
 
Homme Frédéric BROUARD
Expert SGBDR & SQL
Inscription : mai 2002
Messages : 12 170
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 : 12 170
Points : 21 867
Points : 21 867
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 * * * * *
SQLpro est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/05/2005, 15h37   #26
LeoAnderson
Expert Confirmé
 
Avatar de LeoAnderson
 
Inscription : septembre 2004
Messages : 2 940
Détails du profil
Informations forums :
Inscription : septembre 2004
Messages : 2 940
Points : 3 028
Points : 3 028
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 ?
LeoAnderson est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 04/06/2005, 14h25   #27
remika
Membre chevronné
 
Avatar de remika
 
Inscription : septembre 2004
Messages : 807
Détails du profil
Informations personnelles :
Âge : 29

Informations forums :
Inscription : septembre 2004
Messages : 807
Points : 768
Points : 768
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
Citation:
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é...
remika est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/07/2005, 17h23   #28
Xo
Expert Confirmé
 
Avatar de Xo
 
Inscription : janvier 2005
Messages : 2 701
Détails du profil
Informations personnelles :
Âge : 40

Informations forums :
Inscription : janvier 2005
Messages : 2 701
Points : 3 952
Points : 3 952
Envoyer un message via Skype™ à Xo
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
Xo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/08/2005, 09h58   #29
Médiat
Inactif
 
Avatar de Médiat
 
Inscription : décembre 2003
Messages : 1 946
Détails du profil
Informations forums :
Inscription : décembre 2003
Messages : 1 946
Points : 1 934
Points : 1 934
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.
Médiat est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/02/2006, 22h31   #30
Xo
Expert Confirmé
 
Avatar de Xo
 
Inscription : janvier 2005
Messages : 2 701
Détails du profil
Informations personnelles :
Âge : 40

Informations forums :
Inscription : janvier 2005
Messages : 2 701
Points : 3 952
Points : 3 952
Envoyer un message via Skype™ à Xo
  • 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
Xo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/02/2006, 23h38   #31
Xo
Expert Confirmé
 
Avatar de Xo
 
Inscription : janvier 2005
Messages : 2 701
Détails du profil
Informations personnelles :
Âge : 40

Informations forums :
Inscription : janvier 2005
Messages : 2 701
Points : 3 952
Points : 3 952
Envoyer un message via Skype™ à Xo
  • 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
Xo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 04/02/2006, 07h24   #32
Médiat
Inactif
 
Avatar de Médiat
 
Inscription : décembre 2003
Messages : 1 946
Détails du profil
Informations forums :
Inscription : décembre 2003
Messages : 1 946
Points : 1 934
Points : 1 934
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
Médiat est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/02/2006, 22h27   #33
Xo
Expert Confirmé
 
Avatar de Xo
 
Inscription : janvier 2005
Messages : 2 701
Détails du profil
Informations personnelles :
Âge : 40

Informations forums :
Inscription : janvier 2005
Messages : 2 701
Points : 3 952
Points : 3 952
Envoyer un message via Skype™ à Xo
  • 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
Xo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/05/2006, 16h45   #34
cortex024
Membre extrêmement actif
 
Avatar de cortex024
 
Inscription : avril 2005
Messages : 1 273
Détails du profil
Informations forums :
Inscription : avril 2005
Messages : 1 273
Points : 1 011
Points : 1 011
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.
cortex024 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/05/2006, 19h32   #35
Médiat
Inactif
 
Avatar de Médiat
 
Inscription : décembre 2003
Messages : 1 946
Détails du profil
Informations forums :
Inscription : décembre 2003
Messages : 1 946
Points : 1 934
Points : 1 934
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
Médiat est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/08/2006, 14h45   #36
Xo
Expert Confirmé
 
Avatar de Xo
 
Inscription : janvier 2005
Messages : 2 701
Détails du profil
Informations personnelles :
Âge : 40

Informations forums :
Inscription : janvier 2005
Messages : 2 701
Points : 3 952
Points : 3 952
Envoyer un message via Skype™ à Xo
  • 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
Xo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/09/2006, 11h03   #37
Xo
Expert Confirmé
 
Avatar de Xo
 
Inscription : janvier 2005
Messages : 2 701
Détails du profil
Informations personnelles :
Âge : 40

Informations forums :
Inscription : janvier 2005
Messages : 2 701
Points : 3 952
Points : 3 952
Envoyer un message via Skype™ à Xo
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
Xo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/04/2007, 17h00   #38
mboubidi
Membre éclairé
 
Avatar de mboubidi
 
Homme
DBA Oracle
Inscription : novembre 2006
Messages : 306
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 34
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 : 317
Points : 317
Envoyer un message via MSN à mboubidi
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
Type de fichier : rar FRM-XXXXX.rar (58,1 Ko, 7 affichages)
mboubidi est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/04/2007, 19h27   #39
fadace
Rédacteur/Modérateur
 
Avatar de fadace
 
Homme Fabien Celaia
Administrateur de base de données
Inscription : octobre 2002
Messages : 3 858
Détails du profil
Informations personnelles :
Nom : Homme Fabien Celaia
Âge : 42
Localisation : Suisse

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

Informations forums :
Inscription : octobre 2002
Messages : 3 858
Points : 14 309
Points : 14 309
Envoyer un message via ICQ à fadace Envoyer un message via Skype™ à fadace
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 !
fadace est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/04/2007, 14h39   #40
attila771
Membre habitué
 
Homme Gaëtan
Développeur Oracle
Inscription : mai 2006
Messages : 124
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 : 124
Points : 131
Points : 131
Quand tu parle d'aide c'est genre les triggers,order by,group By jointure naturel ect...?
attila771 est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Actualité déjà publiée
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 04h40.


 
 
 
 
Partenaires

Hébergement Web