2017-07-06 41 views
0

SQLAlchemyとPostgresを使用してフラスコアプリケーションを作成しています。私はこれでかなり緑色なので、私はフィードバックをいただければ幸いです。しかし、私の直接の質問は、次のモデルのクエリを構築することです。 SQLAlchemyのクエリでは複数の結合を含むSQLAlchemyクエリ

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 

:私は、クエリから希望何

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) 

は、次のクエリが返すものと同様のテーブルを返すことです。私はuserIdとorderDelivery変数をルートとセッションからクエリに渡します - @app.route('/user/order/<order_date>') | session['userID']:ログイン時に確立されます。

おかげ

+1

多分[this](https://stackoverflow.com/questions/27392661/sqlalchemy-left-join-using-subquery)があなたを助けることができます。[this](https://stackoverflow.com/questions/30311354)/sqlalchemy-joined-with-subquery-issue)を参照してください。 「高度な結合のターゲティングと適応」のトピックの[theicial documentation](http://docs.sqlalchemy.org/en/latest/orm/query.html)もご確認ください –

答えて

2

私が正しくあなたを理解している場合は、注文がサブクエリから来(Item, Price, Order) entititesのタプルを照会したいと思います。これについては、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) 

と生産SQL SQLiteのに対してコンパイル:

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') 

を私は」:

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にあなたの文を渡すことができます以前のアプローチを使用することが推奨されています。

+0

遅れてごめんなさい - これは完璧です。本当に広いテーブルを返す私の最初のSQLクエリよりも理にかなっています。 –

+0

Heh、それはまだ広いですが、エンティティオブジェクトは多数の列を隠します。 –

関連する問題