86 votes

Comment compter les lignes avec SELECT COUNT(*) avec SQLAlchemy ?

J'aimerais savoir s'il est possible de générer un SELECT COUNT(*) FROM TABLE dans SQLAlchemy sans le demander explicitement avec la commande execute() . Si j'utilise :

session.query(table).count()

il génère alors quelque chose comme :

SELECT count(*) AS count_1 FROM
    (SELECT table.col1 as col1, table.col2 as col2, ... from table)

qui est nettement plus lent dans MySQL avec InnoDB. Je cherche une solution qui n'exige pas que la table ait une clé primaire connue, comme le suggère le document Obtenir le nombre de lignes dans un tableau en utilisant SQLAlchemy .

96voto

pi. Points 6026

J'ai réussi à obtenir le SELECT suivant avec SQLAlchemy sur les deux couches.

SELECT count(*) AS count_1
FROM "table"

Utilisation de la couche d'expression SQL

from sqlalchemy import select, func, Integer, Table, Column, MetaData

metadata = MetaData()

table = Table("table", metadata,
              Column('primary_key', Integer),
              Column('other_column', Integer)  # just to illustrate
             )   

print select([func.count()]).select_from(table)

Utilisation de la couche ORM

Il suffit de sous-classer Query (vous l'avez probablement fait de toute façon) et de fournir un service spécialisé d'aide à la décision. count() comme celle-ci.

from sqlalchemy.sql.expression import func

class BaseQuery(Query):
    def count_star(self):
        count_query = (self.statement.with_only_columns([func.count()])
                       .order_by(None))
        return self.session.execute(count_query).scalar()

Veuillez noter que order_by(None) réinitialise l'ordre de la requête, ce qui n'est pas pertinent pour le comptage.

Cette méthode permet d'obtenir un count(*) sur n'importe quelle requête ORM, qui respectera toutes les règles du filter et join conditions déjà spécifiées.

93voto

Nathan Villaescusa Points 6750

Requête portant sur une seule colonne connue :

session.query(MyTable.col1).count()

28voto

melchoir55 Points 2103

J'avais besoin de faire un comptage d'une requête très complexe avec de nombreuses jointures. J'utilisais les jointures comme des filtres, donc je voulais seulement connaître le nombre d'objets réels. count() était insuffisant, mais j'ai trouvé la réponse dans la documentation ici :

http://docs.sqlalchemy.org/en/latest/orm/tutorial.html

Le code ressemblerait à quelque chose comme ceci (pour compter les objets de l'utilisateur) :

from sqlalchemy import func

session.query(func.count(User.id)).scalar()

14voto

Boris Serebrov Points 4790

Ajout à la Utilisation de la couche ORM dans la réponse acceptée : count(*) peut être fait pour ORM en utilisant la fonction query.with_entities(func.count()) comme ceci :

session.query(MyModel).with_entities(func.count()).scalar()

Il peut également être utilisé dans des cas plus complexes, lorsque nous avons des jointures et des filtres. with_entities après les jointures, sinon SQLAlchemy pourrait soulever l'erreur Don't know how to join erreur.

Par exemple :

  • nous avons User modèle ( id , name ) et Song modèle ( id , title , genre )
  • nous disposons de données sur les chansons des utilisateurs - le UserSong modèle ( user_id , song_id , is_liked ) où user_id + song_id est une clé primaire)

Nous voulons obtenir un certain nombre de chansons rock aimées par les utilisateurs :

SELECT count(*) 
  FROM user_song
  JOIN song ON user_song.song_id = song.id 
 WHERE user_song.user_id = %(user_id)
   AND user_song.is_liked IS 1
   AND song.genre = 'rock'

Cette requête peut être générée de la manière suivante :

user_id = 1

query = session.query(UserSong)
query = query.join(Song, Song.id == UserSong.song_id)
query = query.filter(
    and_(
        UserSong.user_id == user_id, 
        UserSong.is_liked.is_(True),
        Song.genre == 'rock'
    )
)
# Note: important to place `with_entities` after the join
query = query.with_entities(func.count())
liked_count = query.scalar()

L'exemple complet est le suivant aquí .

1voto

Ole Points 11

Si vous utilisez l'approche SQL Expression Style, il existe une autre façon de construire l'instruction de comptage si vous avez déjà votre objet table.

Préparatifs pour obtenir l'objet table. Il existe également différentes manières de procéder.

import sqlalchemy

database_engine = sqlalchemy.create_engine("connection string")

# Populate existing database via reflection into sqlalchemy objects
database_metadata = sqlalchemy.MetaData()
database_metadata.reflect(bind=database_engine)

table_object = database_metadata.tables.get("table_name") # This is just for illustration how to get the table_object                    

L'exécution de la requête de comptage sur le table_object

query = table_object.count()
# This will produce something like, where id is a primary key column in "table_name" automatically selected by sqlalchemy
# 'SELECT count(table_name.id) AS tbl_row_count FROM table_name'

count_result = database_engine.scalar(query)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X