What is the equivalent of Query.count in the SQLAlchemy 1.4 ORM?

Question:

Given a SQLAlchemy ORM model like this

class Foo(Base):
    __tablename__ = 'foo'

    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.String())

In SQLAlchemy 1.4 / 2.0, the ORM’s session.query idiom is being unified with the SQLAlchemy core select function*, so to fetch all Foos we would do

foos = session.execute(Foo).scalars().all()

instead of

foos = session.query(Foo).all()

In the current (sqlalchemy<=1.3) ORM we can obtain the number of Foos in the database with this query:

nfoos = session.query(Foo).count()

But how can we get the count in SQLALchemy 1.4?

session.execute(sa.select(Foo).count())

raises

AttributeError: ‘Select’ object has no attribute ‘count’

session.execute(sa.select(Foo)).count()

raises

AttributeError: ‘ChunkedIteratorResult’ object has no attribute ‘count’

session.execute(sa.select(sa.func.count(Foo)))

raises

sqlalchemy.exc.ArgumentError: SQL expression element expected, got <class '__main__.Foo'>.

This works,

session.execute(sa.select(sa.func.count(Foo.id))).scalars()

but specifying an attribute seems less OO / elegant than the Query.count version. Moreover, it precludes building a query but deferring the decision of whether to retrieve the count or the model instances.

What is the idiomatic way to get the count() of an ORM query in the new SQLAlchemy 1.4 world?


* the session.query() API will still work in 1.4 and later

Answers:

Based on Ilja Everilä‘s comments, it seems that there is no direct equivalent to Query.count in the new ORM-querying API released in SQLAlchemy 1.4 (in beta at the time of writing).

The functional equivalent is to call count(), selecting from a subquery*

from sqlalchemy import func, select

count = (
    session.execute(select(func.count()).select_from(select(Foo).subquery()))
    .scalar_one()
)

Generating this SQL

SELECT count(*) AS count_1 
 FROM (SELECT foo.id AS id, foo.name AS name 
         FROM foo) 
AS anon_1

Counting an attribute, such as the primary key column, generates a simple SELECT COUNT

count = session.execute(select(func.count(Foo.id))).scalar_one()
SELECT count(foo.id) AS count_1 
FROM foo

Query.count is still supported in 1.4, so it can still be used, as can all the ORM features available in 1.3.


* Query.count also selects from a subquery rather than executing SELECT COUNT directly.

If you have constructed a complex query with joins and several conditions, you can count the query results like this:

count_query = query.with_only_columns(func.count(Foo.id))
count = session.execute(count_query).scalar_one()

The idea is to use a copy of the query and replace the selected columns with a single count column.

Answered By: aimfeld

You can use rowcount

# using sqlalchemy

  from sqlalchemy import create_engine

    def connect_to_db():
        """Create database connection."""
        url = f"mysql+pymysql://{user}:{db_pwd}@{host}:{port}/{db_name}"
        try:
            engine = create_engine(url)
            return engine.connect()
        except Exception as e:
            raise e
    
    
    def execute_query(query):
        connection = connect_to_db()
        with connection as con:
            result = con.execute(query)
            return result

    results = execute_query("show tables;")
    print("count = ",results.rowcount)

    output: count =  1298
Answered By: 7guyo

For me – using Flask-Sqlalchemy, with the SQLAlchemy Version 2.X – this worked:

subselect = db.select(Tablename).filter_by(user_id=current_user.id, ...)

select = db.select(db.func.count()).select_from(subselect)

number_of_rows = db.session.execute(query).scalar_one()

Shoutout to @snakecharmerb – on strike

for giving the answer to his/her own question and really helping me out there!

Answered By: ndndinger
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.