【问题标题】:SQLAlchemy Query with Multiple Joins具有多个连接的 SQLAlchemy 查询
【发布时间】:2017-07-06 12:26:45
【问题描述】:

我正在使用 SQLAlchemy 和 Postgres 创建一个烧瓶应用程序。我对此很陌生,所以我将不胜感激。但是,我的直接问题是在以下模型上构建查询。

from app import db
from sqlalchemy import or_, and_


# Items Table
class Item(db.Model):

    __tablename__ = "items"

    id = db.Column(db.Integer, primary_key=True)
    itemName = db.Column(db.String, unique=True, nullable=False)
    measurement = db.Column(db.String, nullable=False)
    defaultPrice = db.Column(db.Float, nullable=False)
    minimumOrder = db.Column(db.Float, nullable=False)
    maximumOrder = db.Column(db.Float, nullable=False)
    orders = db.relationship('Order', back_populates='item')
    prices = db.relationship('Price', back_populates='item')

    def __init__(self, itemName, measurement, defaultPrice,
                 minimumOrder, maximumOrder):
        self.itemName = itemName
        self.measurement = measurement
        self.defaultPrice = defaultPrice
        self.minimumOrder = minimumOrder
        self.maximumOrder = maximumOrder

    def __repr__(self):
        return '<Item {0}>'.format(self.id)


# Users Table
class User(db.Model):

    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    fullName = db.Column(db.String, unique=True, nullable=False)
    userName = db.Column(db.String, unique=True, nullable=False)
    password = db.Column(db.String, nullable=False)
    role = db.Column(db.String, nullable=False)
    orders = db.relationship('Order', back_populates='user')
    prices = db.relationship('Price', back_populates='user')

    def __init__(self, fullName, userName, password, role):
        self.fullName = fullName
        self.userName = userName
        self.password = password
        self.role = role

    def __repr__(self):
        return '<User {0}>'.format(self.userName)


# Availability / Price Table
class Price(db.Model):

    __tablename__ = 'prices'

    id = db.Column(db.Integer, primary_key=True)
    userId = db.Column(db.Integer, db.ForeignKey('users.id'))
    user = db.relationship('User', back_populates='prices')
    itemId = db.Column(db.Integer, db.ForeignKey('items.id'))
    item = db.relationship('Item', back_populates='prices')
    available = db.Column(db.Boolean)
    priceMeasurement = db.Column(db.String)
    price = db.Column(db.Float)

    def __init__(self, userId, itemId, priceMeasurement, price):
        self.userId = userId
        self.itemId = itemId
        self.priceMeasurement = priceMeasurement
        self.price = price

    def __repr__(self):
        return '<Price {0}>'.format(self.price)


# Orders Table
class Order(db.Model):

    __tablename__ = 'orders'

    id = db.Column(db.Integer, primary_key=True)
    userId = db.Column(db.Integer, db.ForeignKey('users.id'))
    user = db.relationship('User', back_populates='orders')
    itemId = db.Column(db.Integer, db.ForeignKey('items.id'))
    item = db.relationship('Item', back_populates='orders')
    orderQuantity = db.Column(db.Float)
    orderMeasurement = db.Column(db.String)
    orderPrice = db.Column(db.Float)
    orderDelivery = db.Column(db.Date)
    orderPlaced = db.Column(db.Date)

    def __init__(self, userId, itemId, orderQuantity,
                 orderMeasurement, orderPrice, orderDelivery, orderPlaced):
        self.userId = userId
        self.itemId = itemId
        self.orderQuantity = orderQuantity
        self.orderMeasurement = orderMeasurement
        self.orderPrice = orderPrice
        self.orderDelivery = orderDelivery
        self.orderPlaced = orderPlaced

    def __repr__(self):
        return '<Order {0}>'.format(self.orderDelivery)

我想从查询中返回一个类似于以下查询返回的表:

SELECT * FROM items
JOIN prices ON prices.itemId=items.id
WHERE prices.userId = 1 AND prices.available = True
LEFT JOIN (
SELECT * FROM orders WHERE orderDelivery = '2017-07-05') as orders
ON orders.itemId=items.id

在 SQLAlchemy 查询中。我会将 userId 和 orderDelivery 变量从路由和会话传递给查询 - @app.route('/user/order/&lt;order_date&gt;') | session['userID'] : 在登录时建立。

谢谢

【问题讨论】:

标签: python postgresql flask sqlalchemy flask-sqlalchemy


【解决方案1】:

如果我理解正确,您想查询 (Item, Price, Order) 实体的元组,其中 Order 来自子查询。这在 Selecting Entities from Subqueries 下的对象关系教程中进行了解释。

In [5]: from datetime import date

In [6]: orders_sq = db.session.query(Order).\
   ...:     filter(Order.orderDelivery == date(2017, 7, 5)).\
   ...:     subquery()

In [7]: orders_alias = db.aliased(Order, orders_sq)

In [8]: query = db.session.query(Item, Price, orders_alias).\
   ...:     join(Price).\
   ...:     outerjoin(orders_alias, Item.orders).\
   ...:     filter(Price.userId == 1,
   ...:            Price.available)

以及针对 SQLite 编译时生成的 SQL:

In [9]: print(query)
SELECT items.id AS items_id, items."itemName" AS "items_itemName", items.measurement AS items_measurement, items."defaultPrice" AS "items_defaultPrice", items."minimumOrder" AS "items_minimumOrder", items."maximumOrder" AS "items_maximumOrder", prices.id AS prices_id, prices."userId" AS "prices_userId", prices."itemId" AS "prices_itemId", prices.available AS prices_available, prices."priceMeasurement" AS "prices_priceMeasurement", prices.price AS prices_price, anon_1.id AS anon_1_id, anon_1."userId" AS "anon_1_userId", anon_1."itemId" AS "anon_1_itemId", anon_1."orderQuantity" AS "anon_1_orderQuantity", anon_1."orderMeasurement" AS "anon_1_orderMeasurement", anon_1."orderPrice" AS "anon_1_orderPrice", anon_1."orderDelivery" AS "anon_1_orderDelivery", anon_1."orderPlaced" AS "anon_1_orderPlaced" 
FROM items JOIN prices ON items.id = prices."itemId" LEFT OUTER JOIN (SELECT orders.id AS id, orders."userId" AS "userId", orders."itemId" AS "itemId", orders."orderQuantity" AS "orderQuantity", orders."orderMeasurement" AS "orderMeasurement", orders."orderPrice" AS "orderPrice", orders."orderDelivery" AS "orderDelivery", orders."orderPlaced" AS "orderPlaced" 
FROM orders 
WHERE orders."orderDelivery" = ?) AS anon_1 ON items.id = anon_1."itemId" 
WHERE prices."userId" = ? AND prices.available = 1

另外,您也可以简单地将您的声明传递给Query.from_statement,并进行一些修复和更改:

In [45]: query2 = db.session.query(Item, Price, Order).\
    ...:     from_statement(db.text("""
    ...: SELECT * FROM items
    ...: JOIN prices ON prices.itemId=items.id
    ...: LEFT JOIN (
    ...: SELECT * FROM orders WHERE orderDelivery = :orderDelivery) as orders
    ...: ON orders.itemId=items.id
    ...: WHERE prices.userId = :userId AND prices.available
    ...: """)).\
    ...:     params(userId=1, orderDelivery='2017-07-05')

但我建议使用前一种方法,因为它与数据库无关。

【讨论】:

  • 抱歉耽搁了 - 这是完美的。比我返回一个非常宽的表的初始 SQL 查询更有意义。
  • 嘿,下面还是很宽的,但是实体对象隐藏了很多列。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-24
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-24
  • 2018-12-13
相关资源
最近更新 更多