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 :

Cumul temporel du nombre d'espèces distinctes par date


Sujet :

Langage SQL

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    366
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 366
    Points : 133
    Points
    133
    Par défaut Cumul temporel du nombre d'espèces distinctes par date
    Salut à vous,

    Je bloque sur une requête SQL qui de premier abord me semblait "basique".
    Je travaille sur une base SQLite/Spatialite, mais je peux aussi la faire sur une base PostGreSQL/PostGis, si jamais c'était plus simple.

    Voici la table d'origine très simplifiée : une table d'observations d'espèces, avec notamment un champ date d'observation (dateobs), et un champ espèce (espece) :

    dateobs espece
    01/01/2024 Oiseau bleu
    01/01/2024 Aigle noir
    02/01/2024 Oiseau bleu
    02/01/2024 Flamand rose
    03/01/2024 Rougegorge

    Ce que je souhaiterais, c'est avoir le nombre cumulé d'espèces différentes, observées à chaque date, sous cette forme :
    dateobs cumul_nb_especes Liste_especes
    01/01/2024 2 Oiseau bleu + Aigle noir
    02/01/2024 3 Oiseau bleu + Aigle noir + Flamand rose
    03/01/2024 4 Oiseau bleu + Aigle noir + Flamand rose + Rougegorge
    (j'ai ajouté un champ "liste Espèce", juste pour illustrer, car il ne sera pas calculé, la table ayant plusieurs milliers d'espèces)

    Est-ce que quelqu'un ici arriverait à écrire la requête SQL qui ferait cette synthèse ?

    J'ai tenté de demander à un célèbre agent conversationnel, et sa proposition n'a pas fonctionné (mais j'ai peut-être mal formulé la question).
    Voici sa proposition :
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    WITH CumulativeSpecies AS (
        SELECT
            dateobs,
            espece,
            ROW_NUMBER() OVER (PARTITION BY espece ORDER BY dateobs) AS species_first_seen
        FROM matable)
     
    SELECT
        datebobs,
        COUNT(DISTINCT espece) AS cumulative_species_count
    FROM CumulativeSpecies
    WHERE species_first_seen = 1
    GROUP BY dateobs
    ORDER BY dateobs;

    Un grand merci d'avance !!!

    Sylvain M.

  2. #2
    Expert éminent
    Avatar de Séb.
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    5 197
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 197
    Points : 8 412
    Points
    8 412
    Billets dans le blog
    17
    Par défaut
    Il y a plusieurs approches possibles.

    Avec une fonction fenêtrée et en passant par un résultat intermédiaire (les COUNT(DISTINCT) fenêtrés n'étant pas supportés) :

    with
    	dataset (dateobs, espece) as (
    		values
    			('01/01/2024', 'Oiseau bleu'),
    			('01/01/2024', 'Aigle noir'),
    			('02/01/2024', 'Oiseau bleu'),
    			('02/01/2024', 'Flamand rose'),
    			('03/01/2024', 'Rougegorge')
    	),
    	rapport (espece, premiere_dateobs) as (
    		select all espece, min(dateobs)
    		from dataset
    		group by espece
    	)
    select all 
    	premiere_dateobs as dateobs, 
    	sum(count(*)) over (order by premiere_dateobs asc) as cumul_nb_especes
    from rapport
    group by 1
    order by 1 asc;
    Avec une sous-requête corrélée dans le SELECT :

    with dataset (dateobs, espece) as (
    	values
    		('01/01/2024', 'Oiseau bleu'),
    		('01/01/2024', 'Aigle noir'),
    		('02/01/2024', 'Oiseau bleu'),
    		('02/01/2024', 'Flamand rose'),
    		('03/01/2024', 'Rougegorge')
    )
    select distinct
    	dateobs,
    	(select count(distinct espece) from dataset where dateobs <= d.dateobs) as cumul_nb_especes
    from dataset as d
    order by 1 asc;
    Tu dois aussi pouvoir le faire avec une auto-jointure.

    Testées OK sur SQLite et PostgreSQL.

    Bien sûr dans la pratique il faudra que la colonne dateobs soit bien du type DATE. J'ai laissé les JJ/MM/AAAA par pure flemme
    Un problème exposé clairement est déjà à moitié résolu
    Keep It Smart and Simple

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    366
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 366
    Points : 133
    Points
    133
    Par défaut
    Super : merci beaucoup Séb.

    Les 2 requêtes ont fonctionné sur ma base de données réelle, mais la 1ere s’exécute quasi instantanément, alors que la 2e met près de 20 secondes (sur un petit jeu de données de 2500 observations).
    Du coup, je vais me pencher sur la 1ere pour essayer de la comprendre.

    Même si ça fait des années que je pratique le SQL, je reste débutant, et il y a 2 notions que je ne comprends pas ici. Je vais faire des recherches, mais au cas où, si tu veux m'expliquer les principes du select all et du group by 1 order by 1 asc; ?

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    366
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 366
    Points : 133
    Points
    133
    Par défaut
    Bon, je me suis fait aider (toujours par le célèbre "agent"), et j'ai compris les notions.
    Du coup, j'aurais écris comme ceci :
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    with
    	rapport (espece, premiere_dateobs) as (
    		select espece, min(dateobs)
    		from matable
    		group by espece
    	)
    select
    	premiere_dateobs as dateobs, 
    	sum(count(*)) over (order by premiere_dateobs asc) as cumul_nb_especes
    from rapport
    group by dateobs
    order by dateobs asc;

    Merci encore !

  5. #5
    Expert éminent
    Avatar de Séb.
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    5 197
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 197
    Points : 8 412
    Points
    8 412
    Billets dans le blog
    17
    Par défaut
    si tu veux m'expliquer les principes du select all
    SELECT ALL est le SELECT par défaut => Donne toutes les lignes, doublons compris
    L'autre est SELECT DISTINCT => Donne les lignes dédoublonnées

    et du group by 1 order by 1 asc; ?
    C'est l'indicateur ordinal de colonne, ça évite de mentionner les colonnes en toutes lettres
    => Ici on groupe sur la 1re colonne du SELECT
    => Ici on trie sur la 1re colonne du SELECT
    Je crois que cette syntaxe est obsolète selon ANSI-SQL
    Un problème exposé clairement est déjà à moitié résolu
    Keep It Smart and Simple

  6. #6
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 849
    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 849
    Points : 52 972
    Points
    52 972
    Billets dans le blog
    6
    Par défaut
    GROUP BY 1 n'existe pas en SQL... Et c'est très dangereux...

    ORDER BY 1 existe bien et c'est tout aussi dangereux...

    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/ * * * * *

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    366
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 366
    Points : 133
    Points
    133
    Par défaut
    Merci @SQLpro pour ces précisions/avertissements 😃

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 08/03/2017, 09h46
  2. [Toutes versions] Requête SQL : nombre de valeurs distinctes par regroupement
    Par SylvainM dans le forum Requêtes et SQL.
    Réponses: 13
    Dernier message: 07/03/2014, 09h51
  3. Limiter le nombre d'enregistrements renvoyés par un SELECT
    Par Wilco dans le forum Bases de données
    Réponses: 3
    Dernier message: 17/11/2004, 13h47
  4. Compter le nombre d'enreg retournés par un DBExtract
    Par Sylvain James dans le forum XMLRAD
    Réponses: 2
    Dernier message: 02/11/2004, 14h15
  5. [SYBASE] nombre de ligne impactée par UPDATE
    Par metheorn dans le forum Sybase
    Réponses: 3
    Dernier message: 14/05/2004, 16h47

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