2011-11-04 13 views
5

Korzystanie z SQLAlchemy Core (nie ORM), próbuję INSERT wielu wierszy przy użyciu podzapytania w wartości. MySQL, rzeczywista SQL będzie wyglądać mniej więcej tak:Jak wstawić wiele wartości z podzapytaniem za pomocą SQLAlchemy Core?

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

Ale tylko wydaje się być w stanie wykorzystać podzapytania przy użyciu metody values() na insert() klauzuli, która pozwala tylko mi zrobić jedną wkładkę naraz. Chciałbym wstawić wiele wartości naraz, przekazując je wszystkie do metody Connection 's jako execute() jako listę parametrów wiązania, ale to nie wydaje się być obsługiwane.

Czy można zrobić to, co chcę, w jednym połączeniu z numerem execute()?

Oto niezależna demonstracja. Zauważ, że wykorzystuje to silnik sqlite, który jest doesn't support multiple inserts in the same way as MySQL, ale kod SQLAlchemy nadal kończy się niepowodzeniem w ten sam sposób, co prawdziwa aplikacja 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}, 
    ) 

uruchom go i umiera na ostatniej execute() rozmowy z:

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

Mam przeczucie, że robisz to źle - obecnie chcesz wykonać podzapytanie dla każdego rekordu. A ponieważ używasz SQLAlchemy Core, oznacza to, że wszystkie SQL będą wykonywane dokładnie tak, jak je dostarczasz. – plaes

+0

@plaes yep to dokładnie to, co chcę zrobić (wykonać podzapytanie dla każdego pojedynczego rekordu), musisz tylko zaufać mi, że ma to więcej sensu w prawdziwej aplikacji ':)'. Ale problem polega na tym, że SQLAlchemy ** nie wykonuje ** dokładnie tego, co dostarczam, i odmawia przetworzenia wyrażenia 'Select' expression': (' – Day

Odpowiedz

4

Zamiast dostarczać oświadczenie podselekcji jako wartość parametru, trzeba umieścić go w 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

Fantastic, który działa dzięki uprzejmości.) Uratowałeś mnie przed wielokrotnymi rundami do bazy danych - teraz mogę zrobić wszystko w jednym zapytaniu, które pozwala zaoszczędzić ** ** czasu, kiedy baza danych znajduje się po drugiej stronie świata – Day

+2

Co się stanie, jeśli 'typ_select' ma dwa pola? –

Powiązane problemy