2011-11-04 66 views
5

使用SQLAlchemy核心(而不是ORM),我想要在值中使用子查询插入多行。对于MySQL,实际的SQL会是这个样子:如何使用SQLAlchemy Core在子查询中插入多个值?

INSERT INTO widgets (name, type) VALUES 
('Melon', (SELECT type FROM widgetTypes WHERE type='Squidgy')), 
('Durian', (SELECT type FROM widgetTypes WHERE type='Spiky')) 

但我只似乎能够使用上insert()条款,只允许我做一次一个刀片的values()方法时要使用子查询。我希望一次插入多个值,将它们全部作为绑定参数列表传递给Connectionexecute()方法,但似乎不支持。

是否可以在​​的单个调用中执行我想要的操作?

这是一个独立的演示。请注意,这使用了sqlite引擎,其中doesn't support multiple inserts in the same way as MySQL,但SQLAlchemy代码仍然以与真正的MySQL应用程序相同的方式失败。

from sqlalchemy import * 

if __name__ == "__main__": 
    # Construct database 
    metadata = MetaData() 
    widgetTypes = Table('widgetTypes', metadata, 
     Column('id', INTEGER(), primary_key=True), 
     Column('type', VARCHAR(), nullable=False), 
    ) 
    widgets = Table('widgets', metadata, 
     Column('id', INTEGER(), primary_key=True), 
     Column('name', VARCHAR(), nullable=False), 
     Column('type', INTEGER(), nullable=False), 
     ForeignKeyConstraint(['type'], ['widgetTypes.id']), 
    ) 
    engine = create_engine("sqlite://") 
    metadata.create_all(engine) 

    # Connect and populate db for testing 
    conn = engine.connect() 
    conn.execute(widgetTypes.insert(), [ 
     {'type': 'Spiky'}, 
     {'type': 'Squidgy'}, 
    ]) 

    # Some select queries for later use. 
    select_squidgy_id = select([widgetTypes.c.id]).where(
     widgetTypes.c['type']=='Squidgy' 
    ).limit(1) 
    select_spiky_id = select([widgetTypes.c.id]).where(
     widgetTypes.c['type']=='Squidgy' 
    ).limit(1) 

    # One at a time works via values() 
    conn.execute(widgets.insert().values(
     {'name': 'Tomato', 'type': select_squidgy_id}, 
    )) 

    # And multiple values work if we avoid subqueries 
    conn.execute(
     widgets.insert(), 
     {'name': 'Melon', 'type': 2}, 
     {'name': 'Durian', 'type': 1}, 
    ) 

    # Check above inserts did actually work 
    print conn.execute(widgets.select()).fetchall() 

    # But attempting to insert many at once with subqueries does not work. 
    conn.execute(
     widgets.insert(), 
     {'name': 'Raspberry', 'type': select_squidgy_id}, 
     {'name': 'Lychee', 'type': select_spiky_id}, 
    ) 

运行它,它死在最后​​通话用:

sqlalchemy.exc.InterfaceError: (InterfaceError) Error binding parameter 1 - probably unsupported type. u'INSERT INTO widgets (name, type) VALUES (?, ?)' (('Raspberry', <sqlalchemy.sql.expression.Select at 0x19f14d0; Select object>), ('Lychee', <sqlalchemy.sql.expression.Select at 0x19f1a50; Select object>))

+0

我有一种直觉,认为你做错了 - 目前你想为每一条记录执行一个子查询。而且由于您使用的是SQLAlchemy Core,这意味着所有的SQL都会按照您提供的那样执行。 – plaes

+0

@plaes yep这正是我想要做的(对每条记录执行一个子查询),你只需要相信我在真实应用程序':)'中更有意义。但问题是,SQLAlchemy **不是正在执行我正在执行的内容,而是拒绝处理'Select'表达式':(' – Day

回答

4

提供的子查询语句的参数值,而不是,你必须把它嵌入到INSERT语句:

type_select = select([widgetTypes.c.id]).where(
     widgetTypes.c.type==bindparam('type_name')) 

insert = widgets.insert({'type': type_select}) 

conn.execute(insert, [ 
    {'name': 'Melon', 'type_name': 'Squidgy'}, 
    {'name': 'Lychee', 'type_name': 'Spiky'}, 
]) 
+0

非常赞赏,谢谢你的帮助。让我不必做多次往返到数据库 - 我现在可以在单个查询中做所有事情,当你的数据库位于世界的另一端时,可以节省大量时间。 – Day

+2

如果'type_select'有两个字段会怎么样? –

相关问题