skip to main | skip to sidebar
Code 18
Manuel du savoir-faire à l'usage des geeks et des curieux
RSS
  • Accueil
  • Le web au Québec
  • Liens
  • Twitter
  • Facebook
  • À propos

lundi 14 novembre 2011

Combien de personnes dans chaque groupe d'âge

Publié par Infinite Loop, à 20 h 11 2 commentaires

Voici un cas réel où j'ai eu à résoudre un problème en classant des individus par groupe d'âge à l'aide d'une base de données Postgres. D'abord, imaginons deux tables : la première "human" contient la liste des personnes avec une propriété "birth" où est stockée la date de naissance qu'on utilisera pour connaître son âge en temps réel. L'autre table, nommée "age_group" contient la définition des groupes d'âges en incluant comme propriétés l'âge minimum et maximum pour faire parti du groupe. Une valeur nulle dans l'âge maximum indique l'infini (pour inclure les immortels comme le Highlander par exemple).

Voici le nécessaire si vous souhaitez reproduire l'exercice :

CREATE TABLE human
(
human_id serial NOT NULL,
firstname character varying(50) NOT NULL,
lastname character varying(50) NOT NULL,
birth date
);

CREATE TABLE age_group
(
group_id serial NOT NULL,
age_min integer NOT NULL,
age_max integer,
group_name character varying(50) NOT NULL
);

INSERT INTO age_group(age_min, age_max, group_name)
VALUES (0, 12, 'Enfant (Fan de Justin Bieber)'),
(13, 17, 'Adolescent boutonneux'),
(18, 25, 'Jeune adulte fringant'),
(26, 54, 'Adulte'),
(55, 65, 'Retraité Liberté 55'),
(65, null, 'Bel âge (Les résidences Soleil!)');

INSERT INTO human (firstname, lastname, birth)
VALUES ('Marge', 'Simpson', '1963-06-08'),
('Homer', 'Simpson', '1962-01-31'),
('Bart', 'Simpson', '1997-09-04'),
('Lisa', 'Simpson', '1999-06-06'),
('Maggie', 'Simpson', '2002-07-27'),
('Milhouse', 'Van Houten', '1997-08-08'),
('Montgomery', 'Burns', '1912-03-13'),
('Abraham', 'Simpson', '1914-07-27');
NB. Évidemment, les dates de naissance des personnages des Simpsons sont 100% arbitraires puisqu'ils ne vieillissent pas depuis plus de 20 ans!

À partir de ces données, comment peut-on connaître le nombre de personnes dans chaque groupe d'âge (incluant les groupes vides) ? L'objectif est d'obtenir comme résultat des statistiques comme celles-ci :



À l'aide d'une sous-requête lancée sur chacun des enregistrements, on peut obtenir au mieux une seule information relative au groupe d'âge :
SELECT h.*, (SELECT group_name FROM age_group as tag WHERE extract('year' from age(h.birth)) BETWEEN tag.age_min AND COALESCE(tag.age_max, 200)) as group_name
FROM human as h
ORDER BY group_name
En se basant sur le calcul de l'âge pour déterminer le groupe relié, voici 3 façons d'écrire un énoncé SQL pour arriver exactement au même résultat.

Méthode 1
SELECT ag.group_id, ag.group_name, ag.age_min, ag.age_max, COUNT(t.human_id) as nb
FROM human as h
INNER JOIN (
SELECT human_id, (SELECT group_id FROM age_group as tag WHERE extract('year' from age(birth)) BETWEEN tag.age_min AND COALESCE(tag.age_max, 1000)) as group_id
FROM human
) as t ON t.human_id = h.human_id
RIGHT JOIN age_group as ag ON ag.group_id = t.group_id
GROUP BY ag.group_id, ag.group_name, ag.age_min, ag.age_max
ORDER BY ag.age_min
Méthode 2

Il sera possible de simplifier l'énoncé un peu :
-- requête simplifiée
SELECT ag.group_id, ag.group_name, ag.age_min, ag.age_max, COUNT(h.human_id) as nb
FROM human as h
RIGHT JOIN age_group as ag ON ag.group_id = (SELECT group_id FROM age_group as tag WHERE extract('year' from age(h.birth)) BETWEEN tag.age_min AND COALESCE(tag.age_max, 1000))
GROUP BY ag.group_id, ag.group_name, ag.age_min, ag.age_max
ORDER BY ag.age_min
Méthode 3

Ou encore, une méthode alternative en réécrivant la requête SQL complètement différemment :
-- façon alternative
SELECT ag.group_id, ag.group_name, ag.age_min, ag.age_max, COUNT(tmp.human_id) as nb
FROM age_group as ag
LEFT JOIN (
SELECT tag.group_id, h.human_id
FROM human as h
CROSS JOIN age_group as tag
WHERE extract('year' from age(h.birth)) BETWEEN tag.age_min AND COALESCE(tag.age_max, 1000)
) as tmp ON ag.group_id = tmp.group_id
GROUP BY ag.group_id, ag.group_name, ag.age_min, ag.age_max
ORDER BY ag.age_min
Je serais curieux de savoir laquelle vous préférez et pourquoi. Avec un gros volume de données, il serait possible d'ajouter une colonne à la table "human" pour stocker le groupe d'âge pour éviter le calcul à chaque appel mais il serait nécessaire de maintenir la donnée avec un trigger sur la date de naissance et sur la table des groupes d'âges en cas de changement (où il serait nécessaire de mettre à jour toutes les fiches des personnes). Vous avez d'autres suggestions ?


Tags: PostgreSQL

2 réponses à "Combien de personnes dans chaque groupe d'âge"

  1. Syndrael a dit...
    17 novembre 2011 à 09 h 13

    J'avais fait un super commentaire il vient d'être effacé suite à une erreur de Blogger..pfff..

    Infinite Loop a dit...
    17 novembre 2011 à 10 h 32

    Oups! Tu te souviens des grandes lignes ?


Publier un commentaire

Message plus récent Messages plus anciens Accueil
S'abonner à : Publier des commentaires (Atom)
    Suivre @code18 sur Twitter

    Catégories

    • Apache (21)
    • Citations (167)
    • Club Vidéo (24)
    • Coffre à outils (56)
    • CSS (8)
    • Curiosités (117)
    • Design Pattern (2)
    • Drupal (8)
    • Easter Eggs (22)
    • Extensions Firefox (20)
    • GIMP (7)
    • Histoire (21)
    • HTML (32)
    • Humour (57)
    • Intégration (34)
    • iPod (12)
    • JavaScript (110)
    • Jeu de combat (6)
    • Le coin du geek (128)
    • Liens (12)
    • Linux (56)
    • Livres (78)
    • Lois et principes (46)
    • Marché des saveurs (26)
    • Mathématique (18)
    • Mobile (5)
    • Montréal (32)
    • Musique (112)
    • Pancartes et écriteaux (16)
    • Perl (8)
    • Pérou (1)
    • PHP (130)
    • PostgreSQL (44)
    • Programmation (105)
    • Saviez-vous que (55)
    • Sécurité (22)
    • SEO (5)
    • SQL Server (22)
    • Vieilles publicités (6)
    • Virtualisation (8)
    • Voyages (1)
    • Zend Framework (26)

    Divers

    Archives

    • ►  2015 (6)
      • ►  août 2015 (1)
      • ►  juillet 2015 (1)
      • ►  février 2015 (3)
      • ►  janvier 2015 (1)
    • ►  2014 (8)
      • ►  décembre 2014 (1)
      • ►  novembre 2014 (1)
      • ►  octobre 2014 (1)
      • ►  août 2014 (2)
      • ►  juillet 2014 (2)
      • ►  janvier 2014 (1)
    • ►  2013 (53)
      • ►  décembre 2013 (2)
      • ►  novembre 2013 (1)
      • ►  octobre 2013 (3)
      • ►  septembre 2013 (2)
      • ►  août 2013 (5)
      • ►  juillet 2013 (3)
      • ►  juin 2013 (5)
      • ►  mai 2013 (3)
      • ►  avril 2013 (7)
      • ►  mars 2013 (7)
      • ►  février 2013 (11)
      • ►  janvier 2013 (4)
    • ►  2012 (105)
      • ►  décembre 2012 (8)
      • ►  novembre 2012 (5)
      • ►  octobre 2012 (4)
      • ►  septembre 2012 (1)
      • ►  août 2012 (8)
      • ►  juillet 2012 (7)
      • ►  juin 2012 (7)
      • ►  mai 2012 (10)
      • ►  avril 2012 (13)
      • ►  mars 2012 (15)
      • ►  février 2012 (15)
      • ►  janvier 2012 (12)
    • ▼  2011 (146)
      • ►  décembre 2011 (14)
      • ▼  novembre 2011 (11)
        • Le plaisir insoupçonné de manger du Velveeta
        • Choisir le bon symbole
        • Citation no. 140 sur le voyage
        • Une petite leçon d'humilité
        • Ne laissez pas le chaos l'emporter
        • Citation no. 139 sur les logiciels
        • À l'attention des ados révoltés
        • Connaître la version de SQL Server pour les nuls
        • Combien de personnes dans chaque groupe d'âge
        • 20 choses supplémentaires à savoir sur Google (par...
        • Bubblesort en JavaScript
      • ►  octobre 2011 (12)
      • ►  septembre 2011 (13)
      • ►  août 2011 (15)
      • ►  juillet 2011 (17)
      • ►  juin 2011 (18)
      • ►  mai 2011 (15)
      • ►  avril 2011 (9)
      • ►  mars 2011 (7)
      • ►  février 2011 (3)
      • ►  janvier 2011 (12)
    • ►  2010 (398)
      • ►  décembre 2010 (29)
      • ►  novembre 2010 (28)
      • ►  octobre 2010 (32)
      • ►  septembre 2010 (34)
      • ►  août 2010 (22)
      • ►  juillet 2010 (35)
      • ►  juin 2010 (42)
      • ►  mai 2010 (36)
      • ►  avril 2010 (37)
      • ►  mars 2010 (34)
      • ►  février 2010 (32)
      • ►  janvier 2010 (37)
    • ►  2009 (430)
      • ►  décembre 2009 (32)
      • ►  novembre 2009 (34)
      • ►  octobre 2009 (33)
      • ►  septembre 2009 (37)
      • ►  août 2009 (37)
      • ►  juillet 2009 (39)
      • ►  juin 2009 (38)
      • ►  mai 2009 (37)
      • ►  avril 2009 (35)
      • ►  mars 2009 (37)
      • ►  février 2009 (32)
      • ►  janvier 2009 (39)
    • ►  2008 (84)
      • ►  décembre 2008 (34)
      • ►  novembre 2008 (39)
      • ►  octobre 2008 (11)

    Abonnés

Copyright © All Rights Reserved. Code 18 | Converted into Blogger Templates by Theme Craft