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

PHP & Base de données Discussion :

Somme et date range


Sujet :

PHP & Base de données

  1. #1
    Membre averti
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 124
    Points : 310
    Points
    310
    Par défaut Somme et date range
    Bonjour,

    Je cherche à obtenir les chiffres d'affaires annuel de mes ventes.
    Là ou je sèche, c'est que mon exercice comptable n'est pas du 01/01 au 31/12 mais du 01/09 au 31/08

    Du 01/01 au 31/12 j'utiliserai le code ci-dessous
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT YEAR(date_vente) as An, SUM(total_ht_vente) as Total FROM clients__vente GROUP BY YEAR(date_vente) ORDER BY YEAR(date_vente) DESC

    Mais dans mon cas, comment le réaliser?

    Une idée svp ?

  2. #2
    Membre émérite Avatar de darkstar123456
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2008
    Messages
    1 896
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2008
    Messages : 1 896
    Points : 2 835
    Points
    2 835
    Par défaut
    Bonjour,

    Grâce à l'utilisation de BETWEEN :

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT SUM(total_ht_vente) as Total FROM clients__vente WHERE date_vente BETWEEN '2018-09-01' AND '2019-08-31';

    Il est aussi possible d'écrire WHERE date_vente >= '2018-09-01' AND date_vente <= '2019-08-31'

  3. #3
    Membre averti
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 124
    Points : 310
    Points
    310
    Par défaut
    Bonjour Darkstar,

    J'avais pensé à cela, mais j'ai besoin de récupérer le chiffre d'affaire des années passées également.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    01/09/2018 au 31/08/2019 : 20000€
    01/09/2017 au 31/08/2018 : 20000€
    01/09/2016 au 31/08/2017 : 20000€
    etc...
    Et la je sèche complètement.

  4. #4
    Membre émérite Avatar de darkstar123456
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2008
    Messages
    1 896
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2008
    Messages : 1 896
    Points : 2 835
    Points
    2 835
    Par défaut
    A mon avis, en imbriquant des requêtes il devrait y avoir moyen mais c'est illisible et donc un peu dégueulasse ^^

    Personnellement, je commencerais par faire un SELECT MIN(date_vente) FROM clients__vente histoire de connaître la date la plus ancienne.
    Une fois que c'est fait, faire une boucle en PHP de la date maximum (date('Y')) et ensuite boucler de la date max jusqu'à la min (quelque chose comme : for($i = date('Y'); $i >= $date_min; $i--)) et là, dans chaque boucle, tu peux construire les dates et faire le SELECT avec BETWEEN en remplaçant les dates par celles construites

    EDIT :
    Voilà un bout de code plus précis. Attention, l'exécution des requêtes se fait suivant ce que tu utilises (mysqli, PDO, ou autre)
    Code php : 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
    // On imagine qu'on a un classe qui gère la DB
    $db = new ClassQuiGereLesConnexionsDB();
    // On récupère la date minimale
    $sql = "SELECT MIN(date_vente) AS min_date_vente FROM clients__vente";
    $min_date_vente = $db->query($sql)->get_row()->min_date_vente;
    $min_year = date('Y', strtotime($min_date_vente));
    // On va boucler de maintenant à la plus petite année
    $montants = [];
    for ($i = date('Y'); $i >= $min_year; $i--) {
        $sql = "SELECT SUM(total_ht_vente) as Total FROM clients__vente WHERE date_vente BETWEEN '2018-09-01' AND '2019-08-31';";
        $sqlData = [
            ($i - 1) . '-09-01',
            $i . '-08-31',
        ];
        // On exécute notre requête préparée, avec les dates correctes
        $total_ht_vente = $db->exec($db->prepare($sql, $sqlData))->get_row()->Total;
        // On ajoute tout dans $montants, comme ça on garde l'interval aussi :)
        $montants[] = [
            'total' => $total_ht_vente,
            'interval' => $sqlData,
        ];
     
    }
    // Affichage des résultats
    echo PHP_EOL . '<pre>$montants: ' . print_r($montants, true) . '</pre>' . PHP_EOL;

  5. #5
    Membre averti
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 124
    Points : 310
    Points
    310
    Par défaut
    J'avais pensé effectivement à boucler sur la requête SELECT.
    Mais je me demandais s'il n'existait pas une autre possibilité "plus propre".
    J'avais pensé que peut être il existait quelque chose du style GROUP BY (date_range).

  6. #6
    Membre émérite Avatar de darkstar123456
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2008
    Messages
    1 896
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2008
    Messages : 1 896
    Points : 2 835
    Points
    2 835
    Par défaut
    Il vaut souvent mieux faire plein de petites requêtes plutôt que des gros JOIN ou des requêtes imbriquées

  7. #7
    Expert éminent sénior
    Avatar de rawsrc
    Homme Profil pro
    Dev indep
    Inscrit en
    Mars 2004
    Messages
    6 142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Dev indep

    Informations forums :
    Inscription : Mars 2004
    Messages : 6 142
    Points : 16 545
    Points
    16 545
    Billets dans le blog
    12
    Par défaut
    @darkstar123456

    t'es sûr de toi parce que j'aurais plutôt tendance à largement privilégier les gros JOIN sur les colonnes indexées afin de déporter au maximum la charge de travail sur le moteur de la base de données qui est hyper optimisé de ce côté...

  8. #8
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Normalement, les dates de l'exercice comptable (du 01/09 au 31/08) sont fixée dès le départ, et ne changent plus.

    Une autre solution est de :
    • créer une colonne "annee_compta" dans la table "clients__vente".
    • écrire un script PHP qui va effectuer un UPDATE de toute la table, afin d'ajouter l'année compta qui convient à chaque ligne
    • écrire un script PHP qui déterminera l'année compta pour chaque nouvel INSERT dans la table

    Ce qui, au final, simplifie grandement la requête des totaux, qui devrait ressembler à :

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT 
    	DISTINCT CV.annee_compta as An, 
    	(SELECT SUM(CV2.total_ht_vente FROM clients__vente CV2 WHERE CV2.annee_compta = CV.annee_compta) as Total
    FROM clients__vente CV
    ORDER BY CV.annee_compta DESC

    N.B. J'ajoute que le chiffre d'affaire des années passées est aussi censé être fixe et inchangé !
    Par conséquent, on doit pouvoir :
    • créer une table "chiffres_affaire_compta" (id_ca, annee_compta, montat_ht_ca)
    • les "années passées" y seraient listées
    • seule l'"année en cours" serait "en cours" (à actualiser en fin d'année comptable)

    Mais bon, ce ne sont que des réflexions perso "à chaud"...
    Il existe certainement une méthode rodée qui a fait ses preuves.
    Dernière modification par Invité ; 27/11/2019 à 15h50.

  9. #9
    Membre émérite Avatar de darkstar123456
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2008
    Messages
    1 896
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2008
    Messages : 1 896
    Points : 2 835
    Points
    2 835
    Par défaut
    @rawsrc Hmmm il faudrait que je sois plus clair dans mon explication ! C'est comme pour tout, y'a des nuances ^^

    Déjà, si tu as des OR dans ta requête, vaut mieux pas utiliser de JOIN =) bon, sauf si tu t'attends pas à avoir beaucoup de données dans tes tables évidemment ^^

    Chaque JOIN créée une table temporaire, donc si tu travailles sur des tables qui contiennent beaucoup de données et qu'il faut beaucoup croiser (beaucoup de JOIN), il vaut clairement mieux faire beaucoup de "petites requêtes" car tu vas te retrouver avec une table temporaire ENORME

    Perso, j'ai travaillé sur des tables avec une douzaine de millions de lignes donc tu ne fais pas n'importe quoi là-dedans.
    Malheureusement pour moi, certaines requêtes m'obligeaient à cumuler des JOIN et des OR... du coup, la seule solution était le cache mais en tout cas, tu vois direct que c'est ça qui foutait la merde.
    Toutes mes requêtes allaient super vites malgré le nombre de lignes en DB mais dès l'ajout de ces règles (suivant ce que le user avait choisi en front) ça devenait super lent

    Après, si je parlais de ça, c'est que j'ai l'impression que les gens se disent que c'est mal de faire plein de petites requêtes mais pas vraiment.
    Si tu fais 10 requêtes de 0.01s, ça ne fait jamais que 0.1s de prise alors qu'une requête avec des JOIN et des OR peut potentiellement prendre plus de temps.


    EDIT : Je n'ai pas vraiment de sources pour étayer mon propos. Je tiens ça en partie de mon expérience et de notre admin sys du boulot =D

  10. #10
    Membre averti
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 124
    Points : 310
    Points
    310
    Par défaut
    C'est animé, c'est cool
    J'ai tenté la proposition de Jreaux62 en omettant la colonne "annee_compta" car tout mon code php et sql est réalisé et que j'aimerai éviter d'apporter des modifications.
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT DISTINCT YEAR(CV.date_vente) as An, 
    (SELECT SUM(CV2.total_ht_vente) FROM clients__vente CV2 WHERE YEAR(CV2.date_vente) = An) as Total 
    FROM clients__vente CV
    Le résultat est là, par contre, ça prend énormément de temps.
    Pour traiter 10 000 lignes, ça a pris 50 secondes.

  11. #11
    Membre émérite Avatar de darkstar123456
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2008
    Messages
    1 896
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2008
    Messages : 1 896
    Points : 2 835
    Points
    2 835
    Par défaut
    Si ta colonne CV.date_vente n'est pas de type DATETIME mais un simple DATE, essaye de rajouter un INDEX dessus pour accélérer la requête (s'il n'y en a pas).
    S'il y a déjà un INDEX, je t'invite à séparer les requêtes car les requêtes imbriquées créées, elles aussi, des tables temporaires.

  12. #12
    Invité
    Invité(e)
    Par défaut
    Une variante de la proposition de darkstar123456 :

    // 1- On récupère toutes les ANNEES
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $sql_annees = "SELECT DISTINCT(YEAR(date_vente)) AS annee FROM clients__vente ORDER BY annee DESC";
    // 2- On boucle sur les années
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $montants = [];
    foreach( ..... as $annee_compta ) {
        // Total pour cette année
        $sql = "SELECT SUM(total_ht_vente) as Total FROM clients__vente WHERE date_vente BETWEEN '".($annee_compta-1)."-09-01' AND '".$annee_compta."-08-31';";
    ...
        $montants[$annee_compta] = $row['Total'];
    }
    N.B. Pour participer au débat...
    Je suis plutôt d'accord avec darkstar123456 : si une seule requête commence à devenir trop complexe, je préfère passer par plusieurs petites, plus simples.

    En l'occurrence, il ne suffit pas de mettre "simplement" des JOIN, mais des IF ou CASE * dans la requête SQL:
    • en fonction de la date date_vente, l'année compta pour cette ligne sera YEAR(date_vente) ou (YEAR(date_vente)+1) !

    * Et là, je suis largué, car je ne suis pas "admin BDD".
    Dernière modification par rawsrc ; 27/11/2019 à 17h34.

  13. #13
    Membre averti
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 124
    Points : 310
    Points
    310
    Par défaut
    Ça se fait d'ajouter un INDEX à une colonne DATE ? Je pensais que DATE était naturellement indexé de par sa nature...
    Je vais surement finir par boucler les requêtes SQL effectivement...

  14. #14
    Membre émérite Avatar de darkstar123456
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2008
    Messages
    1 896
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2008
    Messages : 1 896
    Points : 2 835
    Points
    2 835
    Par défaut
    Alors je me trompe peut-être car je ne suis pas sûr à 100% mais il me semble que c'est le type TIMESTAMP qui a une particularité.
    Les champs DATE et DATETIME ne sont pas indexés, et il est déconseillé d'indexer des champs DATETIME car ça créé plus d'index que de résultats xD

  15. #15
    Membre averti
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 124
    Points : 310
    Points
    310
    Par défaut
    Merci pour les renseignements. Je vais partir sur une boucle avec un index sur la colonne date.
    Merci à tous.

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

Discussions similaires

  1. [XL-2007] diagramme en barre avec somme de date
    Par lelou54 dans le forum Excel
    Réponses: 2
    Dernier message: 17/10/2010, 09h23
  2. bo 6.5 et somme suivant dates de paie
    Par gwena2b dans le forum Débuter
    Réponses: 4
    Dernier message: 10/12/2009, 16h07
  3. Faire une somme avec un range
    Par Prekestolen dans le forum Macros et VBA Excel
    Réponses: 11
    Dernier message: 28/01/2009, 17h35
  4. Somme de date en sql/Oracle
    Par zizou771 dans le forum SQL
    Réponses: 10
    Dernier message: 19/06/2008, 14h39
  5. Somme de dates
    Par atn59 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 04/06/2008, 12h14

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