SQLAlchemy:如何按两个字段分组并按日期过滤
在本文中,我们将看到如何在Python中使用 SQLAlchemy 按两个字段对记录进行分组并按日期进行过滤。
由于我们将在本文中使用 MySQL,因此我们还将在Python中安装 MySQL 的 SQL 连接器。但是,除了 SQL 连接器之外,没有任何代码实现会随着数据库的变化而变化。
pip install pymysql
我们将使用 MySQL 中的示例 sakila 数据库。在此,我们将从 sakila 数据库中的支付表中提取一些字段,方法是使用 ` customer_id`和` rental_id`对它们进行分组,并过滤` payment_date`字段上的查询。如果您没有 sakila 数据库并且想在不安装它的情况下继续阅读本文,那么使用下面提到的链接中的 SQL 脚本来创建所需的架构和付款表以及记录。
Sakila 付款表脚本
作为参考,支付表中的前十条记录如下所示——
我们在以下两个示例中查看的 SQL 查询是 -
SELECT
customer_id,
rental_id,
amount,
payment_date
FROM payment
WHERE payment_date > '2005-05-25'
GROUP BY customer_id, rental_id;
方法1:使用SQLAlchemy Core按两个字段分组并按日期过滤:
SQLAlchemy Core 是一个以模式为中心的模型,这意味着一切都被视为数据库的一部分,即行、列、表等。在下面的示例中,我们创建了元数据对象来访问表等数据库对象。使用这个对象,我们得到了`payment`表的元数据。然后使用下面提到的 SQLAlchemy 语法使用此元数据信息查询表。
Syntax: sqlalchemy.engine.base.Engine(sqlalchemy.sql.selectable.Select(*entities).filter(*criterion).group_by(*clauses)).all()
Python3
import sqlalchemy as db
# DEFINE THE ENGINE (CONNECTION OBJECT)
engine = db.create_engine("mysql+pymysql://root:password@localhost/sakila")
# CREATE THE METADATA OBJECT TO ACCESS THE TABLE
meta_data = db.MetaData(bind=engine)
db.MetaData.reflect(meta_data)
# GET THE `payment` TABLE FROM THE METADATA OBJECT
payment = meta_data.tables['payment']
# PREPARING QUERY
query = db.select(
payment.c.customer_id,
payment.c.rental_id,
payment.c.amount,
payment.c.payment_date
).filter(payment.c.payment_date > '2005-05-25') \
.group_by(payment.c.customer_id, payment.c.rental_id)
# EXTRACT THE RECORDS USING THE QUERY AND ENGINE
with engine.connect() as conn:
result = conn.execute(query).all()
# PRINT FIRST 10 RECORDS
for i in range(10):
r = result[i]
print(r.customer_id, "|", r.rental_id, "|", r.amount, "|", r.payment_date)
Python3
from sqlalchemy.orm import sessionmaker
import sqlalchemy as db
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
# DEFINE THE ENGINE (CONNECTIO OBJECT)
engine = db.create_engine("mysql+pymysql://root:password@localhost/sakila")
# AUTOMATICALLY MAP THE TABLE MODEL TO USE IT FOR QUERYING
class Payment(Base):
__table__ = db.Table("payment", Base.metadata, autoload_with=engine)
# CREATE A SESSION OBJECT TO INITIATE QUERY IN DATABASE
Session = sessionmaker(bind=engine)
session = Session()
# PREPARING QUERY USING SQLALCHEMY
result = session.query(
Payment.customer_id,
Payment.rental_id,
Payment.amount,
Payment.payment_date
).filter(Payment.payment_date > '2005-05-25') \
.group_by(Payment.customer_id, Payment.rental_id) \
.all()
# PRINT FIRST 10 RECORDS
for i in range(10):
r = result[i]
print(r.customer_id, "|", r.rental_id, "|", r.amount, "|", r.payment_date)
输出:
方法2:使用SQLAlchemy ORM按两个字段分组,按日期过滤:
SQLAlchemy Core 使用以对象为中心的视图,它将模式与业务对象封装在一起。这是一个更 Pythonic 的实现,因为我们可以看到以类格式表示的表。我们已经使用这个类对象使用下面提到的 SQLAlchemy 语法来查询支付表。
Syntax: sqlalchemy.orm.Query(*entities).filter(*criterion).group_by(*clauses).all()
Python3
from sqlalchemy.orm import sessionmaker
import sqlalchemy as db
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
# DEFINE THE ENGINE (CONNECTIO OBJECT)
engine = db.create_engine("mysql+pymysql://root:password@localhost/sakila")
# AUTOMATICALLY MAP THE TABLE MODEL TO USE IT FOR QUERYING
class Payment(Base):
__table__ = db.Table("payment", Base.metadata, autoload_with=engine)
# CREATE A SESSION OBJECT TO INITIATE QUERY IN DATABASE
Session = sessionmaker(bind=engine)
session = Session()
# PREPARING QUERY USING SQLALCHEMY
result = session.query(
Payment.customer_id,
Payment.rental_id,
Payment.amount,
Payment.payment_date
).filter(Payment.payment_date > '2005-05-25') \
.group_by(Payment.customer_id, Payment.rental_id) \
.all()
# PRINT FIRST 10 RECORDS
for i in range(10):
r = result[i]
print(r.customer_id, "|", r.rental_id, "|", r.amount, "|", r.payment_date)
输出: