Как вставить несколько значений с помощью подзапроса с помощью SQLAlchemy Core? - PullRequest
6 голосов
/ 04 ноября 2011

Используя ядро ​​SQLAlchemy (не ORM), я пытаюсь вставить несколько строк, используя подзапросы в значениях.Для MySQL фактический SQL будет выглядеть примерно так:

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

Но мне кажется, что я могу использовать подзапросы только при использовании метода values() в insert() предложение, которое позволяет мне делать только одну вставку за раз.Я хотел бы вставить несколько значений одновременно, передав их все методу Connection s execute() в виде списка параметров связывания, но это не поддерживается.

Можно ли сделать то, что я хочу, за один вызов execute()?

Вот отдельная демонстрация.Обратите внимание, что здесь используется движок sqlite, который не поддерживает множественные вставки так же, как 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},
    )

Запустите его и он умирает при последнем execute() вызове с:

sqlalchemy.exc.InterfaceError: (InterfaceError) Параметр привязки ошибки 1 - возможно, неподдерживаемый тип.u'INSERT INTO виджеты (имя, тип) VALUES (?,?) '((' Raspberry ',), («Личи»,))

1 Ответ

5 голосов
/ 07 ноября 2011

Вместо предоставления оператора subselect в качестве значения параметра вы должны встроить его в оператор 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'},
])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...