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

Ruby on Rails Discussion :

requete complexe sur plusieurs table avec somme et compte


Sujet :

Ruby on Rails

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Développeur amateur
    Inscrit en
    Janvier 2020
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur amateur

    Informations forums :
    Inscription : Janvier 2020
    Messages : 1
    Points : 1
    Points
    1
    Par défaut requete complexe sur plusieurs table avec somme et compte
    Bonjour,
    Je bidouille un peu RoR en dilettante, essentiellement pour travailler sur des BDD persos avec une interface facile à mettre en place et pratique.
    Jusque là, je m'étais toujours débrouillé seul en cas de problème, mais là, je sèche complètement.

    Mon projet consiste en une BDD dont l'objectif est d'obtenir des stats sur les occurrences de mots dans des corpus de textes.
    J'ai donc une table textes
    Code Ruby : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    create_table "textes", force: :cascade do |t|
        t.string "titre"
        t.string "alpha"
        t.text "contenu"
        t.boolean "fait"
        t.integer "nb_mots", default: 0, null: false
        t.index ["alpha", "titre"], name: "index_textes_on_alpha_and_titre"
      end

    une table lemmes (les lemmes sont les mots en tant qu'entrées dans le dictionnaire)
    Code Ruby : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    create_table "lemmes", force: :cascade do |t|
        t.string "libelle"
        t.string "alpha"
        t.integer "category_id"
        t.integer "textes_compteur", default: 0, null: false
        t.index ["alpha", "libelle"], name: "index_lemmes_on_alpha_and_libelle"
        t.index ["category_id"], name: "index_lemmes_on_category_id"
      end

    Une table compteurs pour les lier :
    Code Ruby : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    create_table "compteurs", force: :cascade do |t|
        t.integer "texte_id"
        t.integer "lemme_id"
        t.integer "occurences", default: 0
        t.index ["lemme_id"], name: "index_compteurs_on_lemme_id"
        t.index ["texte_id", "lemme_id"], name: "index_compteurs_on_texte_id_and_lemme_id", unique: true
        t.index ["texte_id"], name: "index_compteurs_on_texte_id"
      end

    et une table categories qui sert aussi pour la requête :
    Code Ruby : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    create_table "categories", force: :cascade do |t|
        t.string "libelle"
      end

    Je voudrais lister, pour chaque lemme, son libelle, celui de la catégorie associée, le compte du nombre de texte dans lequel il figure, et la somme de toutes les occurences du mot dans lesdits textes, avec éventuellement une sous-requête pour les textes
    En pur SQL, je peux faire ça sans soucis :
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    SELECT lemmes.libelle AS mot,
    	categories.libelle AS categorie,
    	count(compteurs.occurences) AS nb_textes,
    	sum(compteurs.occurences) AS tot_occurences
    FROM lemmes
    	LEFT JOIN compteurs ON lemmes.id = compteurs.lemme_id
    	INNER JOIN categories ON categories.id = lemmes.category_id
    WHERE compteurs.texte_id IN (1, 2)
    GROUP BY compteurs.lemme_id;

    Mais sous rails, j'ai plus de mal à obtenir ce que je veux, combiner directement les méthodes select, group, joins, sum et count semble définitivement une mauvaise idée (surtout à cause de count et sum)
    Pour l'instant, le mieux que j'aie pu obtenir c'est ceci (dans la classe/model Compteur) :
    Code Ruby : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    def self.lemmes_stats(textes = nil)
        textes ||= Texte.select(:id)
        lemmes = Lemme.joins(:category).eager_load(:category)
        results = []
        lemmes.each do |l|
          h = {}
          h[:lemme] = l.libelle
          h[:category] = l.category.libelle
          h[:count] = self.where(lemme_id: l.id, texte_id: textes).count(:occurences)
          h[:sum] = self.where(lemme_id: l.id, texte_id: textes).sum(:occurences)
          results.push(h)
        end
        return results
      end
    Ça fonctionne, mais ça ne me semble ni très élégant, ni dans l'esprit rails, En plus, ça va systématiquement exécuter 2N+1 requêtes. N étant le nombre de lemmes.

    Donc si quelqu'un pouvait me proposer un meilleur moyen d'obtenir une telle liste, je lui en serai reconnaissant. Sinon... ben tant pis, je me contenterait de questionner directment la BDD via DB Browser.
    Merci d'avance !

  2. #2
    Membre actif
    Profil pro
    Problem Solver
    Inscrit en
    Juin 2013
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Problem Solver

    Informations forums :
    Inscription : Juin 2013
    Messages : 138
    Points : 231
    Points
    231
    Par défaut arel > activerecord
    Je te propose de regarder arel et de progresser en faisant des .to_sql régulièrement.
    Voici un gist avec plein d'exemples : https://gist.github.com/abelards/b1a...1e8aa472ad4247

    Si tu fais un scope left_join_compteurs (regarde with_attendance pour un exemple)
    ça finira sûrement par ressembler à du code comme ceci, que tu connais bien (très proche de SQL) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Lemme
    .joins(:categories)
    .left_join_compteurs
    .merge(Compteur.where(texte_id: [1,2]))
    .group(Compteur.arel_table[:lemme_id])
    .select(Lemme.arel_table[:libelle].as('mot'), Categorie.arel_table[:libelle].as('cat'),
      Compteur.arel_table[:occurrences].count.as('nb_textes'), Compteur.arel_table[:occurrences].sum.as('tot_occurrences'))
    et probablement après du Ruby pur

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    .group{|lemme_id, res|
      puts "pour le lemme #{lemme_id} j'ai :"
      res.each {|res| [res.mot, res.cat, res.nb_textes, res.tot_occurrences].inspect }
    }

Discussions similaires

  1. Requete sur plusieurs tables avec TOP
    Par elscorpio dans le forum WinDev
    Réponses: 13
    Dernier message: 09/08/2018, 09h05
  2. [2.x] requete sur plusieurs tables avec "findby"
    Par adel25 dans le forum Symfony
    Réponses: 2
    Dernier message: 02/10/2013, 17h12
  3. Requete complexe sur 2 tables avec dates
    Par fusee2013 dans le forum Langage SQL
    Réponses: 3
    Dernier message: 11/08/2013, 19h56
  4. Requete sur plusieurs table avec les memes champs
    Par broule dans le forum Langage SQL
    Réponses: 4
    Dernier message: 05/02/2010, 19h57
  5. Requete SQL complexe sur plusieurs tables
    Par vnk600 dans le forum Langage SQL
    Réponses: 7
    Dernier message: 13/12/2009, 11h22

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