解決這個問題的一種方法是首先從tool
關係中選擇一組(toolbox_id, name)
元組的集合,其中quantity
滿足。然後divide發現設置了所需工具的名稱,並且您將剩下所需的toolbox_id
。
另外,在這種情況下,更簡單的方法是從滿足數量的工具中選擇工具箱ID的intersection,然後選擇與ID匹配的工具箱。
初始數據
In [51]: db.session.add(Toolbox(tools=[
...: Tool(name='hammer', quantity=1),
...: Tool(name='screwdriver', quantity=3),
...: Tool(name='wrench', quantity=1)]))
In [52]: db.session.add(Toolbox(tools=[
...: Tool(name='hammer', quantity=1),
...: Tool(name='screwdriver', quantity=2),
...: Tool(name='wrench', quantity=1)]))
In [53]: db.session.add(Toolbox(tools=[
...: Tool(name='hammer', quantity=1),
...: Tool(name='screwdriver', quantity=3)]))
In [54]: db.session.add(Toolbox(tools=[
...: Tool(name='hammer', quantity=1),
...: Tool(name='wrench', quantity=1)]))
In [55]: db.session.add(Toolbox(tools=[
...: Tool(name='hammer', quantity=1)]))
In [56]: db.session.commit()
相交
表格的交叉點:
In [9]: tools = db.intersect(*(db.session.query(Tool.toolbox_id).
...: filter(Tool.name == name,
...: Tool.quantity >= quantity)
...: for name, quantity in tool_dict.items())).alias()
然後選擇Toolbox
ES其中id是在路口:
In [10]: db.session.query(Toolbox).filter(Toolbox.id.in_(tools)).all()
Out[10]: [<__main__.Toolbox at 0x7f7ca781c048>]
In [11]: _[0].id
Out[11]: 1
司
形式的CTE從工具的選擇,而CTE的別名,就像我們在內部使用它不遲存在:
In [41]: tools = db.union(*(db.session.query(Tool.toolbox_id, Tool.name).
...: filter(Tool.name == name,
...: Tool.quantity >= quantity)
...: for name, quantity in tool_dict.items())).cte()
In [42]: tools_alias = tools.alias()
表格所需的工具的關係:
In [38]: required_tools = db.union(
...: *(db.select([db.literal(name).label('tool_name')])
...: for name in tool_dict.keys())).alias()
這可能在PostgreSQL進行一些DB的簡單一點,例如,你可以這樣做:
from sqlalchemy.dialects.postgresql import array
required_tools = func.unnest(array(list(tool_dict.keys()))).alias()
進行劃分:
In [63]: db.session.query(tools.c.tool_toolbox_id.distinct()).\
...: filter(~db.session.query().select_from(required_tools).
...: filter(~db.session.query().select_from(tools_alias).
...: filter(tools_alias.c.tool_toolbox_id == tools.c.tool_toolbox_id,
...: tools_alias.c.tool_name == required_tools.c.tool_name).
...: exists().correlate_except(tools_alias)).
...: exists()).all()
Out[63]: [(1)]
的雙重嵌套否定很礙眼,但它回答查詢「找到那些工具箱(IDS)內,如果沒有這樣的必要工具存在,是不是在工具箱」。
爲了獲取所需Toolbox
ES直接就可以調整查詢了一下,從頂層toolbox
關係和工會形成僅在最裏面的級別選擇:
In [16]: tools = db.union(*(db.session.query(Tool.toolbox_id, Tool.name).
...: filter(Tool.name == name,
...: Tool.quantity >= quantity)
...: for name, quantity in tool_dict.items())).alias()
In [17]: db.session.query(Toolbox).\
...: filter(~db.session.query().select_from(required_tools).
...: filter(~db.session.query().select_from(tools).
...: filter(tools.c.tool_toolbox_id == Toolbox.id,
...: tools.c.tool_name == required_tools.c.tool_name).
...: exists().correlate_except(tools)).
...: exists()).all()
Out[17]: [<__main__.Toolbox at 0x7f302f589898>]
In [18]: _[0].id
Out[18]: 1