psycopg2: insert multiple rows with one query

后端 未结 15 2313
谎友^
谎友^ 2020-11-22 09:11

I need to insert multiple rows with one query (number of rows is not constant), so I need to execute query like this one:

INSERT INTO t (a, b) VALUES (1, 2),         


        
相关标签:
15条回答
  • 2020-11-22 09:49

    executemany accept array of tuples

    https://www.postgresqltutorial.com/postgresql-python/insert/

        """ array of tuples """
        vendor_list = [(value1,)]
    
        """ insert multiple vendors into the vendors table  """
        sql = "INSERT INTO vendors(vendor_name) VALUES(%s)"
        conn = None
        try:
            # read database configuration
            params = config()
            # connect to the PostgreSQL database
            conn = psycopg2.connect(**params)
            # create a new cursor
            cur = conn.cursor()
            # execute the INSERT statement
            cur.executemany(sql,vendor_list)
            # commit the changes to the database
            conn.commit()
            # close communication with the database
            cur.close()
        except (Exception, psycopg2.DatabaseError) as error:
            print(error)
        finally:
            if conn is not None:
                conn.close()
    
    0 讨论(0)
  • 2020-11-22 09:49

    If you want to insert multiple rows within one insert statemens (assuming you are not using ORM) the easiest way so far for me would be to use list of dictionaries. Here is an example:

     t = [{'id':1, 'start_date': '2015-07-19 00:00:00', 'end_date': '2015-07-20 00:00:00', 'campaignid': 6},
          {'id':2, 'start_date': '2015-07-19 00:00:00', 'end_date': '2015-07-20 00:00:00', 'campaignid': 7},
          {'id':3, 'start_date': '2015-07-19 00:00:00', 'end_date': '2015-07-20 00:00:00', 'campaignid': 8}]
    
    conn.execute("insert into campaign_dates
                 (id, start_date, end_date, campaignid) 
                  values (%(id)s, %(start_date)s, %(end_date)s, %(campaignid)s);",
                 t)
    

    As you can see only one query will be executed:

    INFO sqlalchemy.engine.base.Engine insert into campaign_dates (id, start_date, end_date, campaignid) values (%(id)s, %(start_date)s, %(end_date)s, %(campaignid)s);
    INFO sqlalchemy.engine.base.Engine [{'campaignid': 6, 'id': 1, 'end_date': '2015-07-20 00:00:00', 'start_date': '2015-07-19 00:00:00'}, {'campaignid': 7, 'id': 2, 'end_date': '2015-07-20 00:00:00', 'start_date': '2015-07-19 00:00:00'}, {'campaignid': 8, 'id': 3, 'end_date': '2015-07-20 00:00:00', 'start_date': '2015-07-19 00:00:00'}]
    INFO sqlalchemy.engine.base.Engine COMMIT
    
    0 讨论(0)
  • 2020-11-22 09:49

    Finally in SQLalchemy1.2 version, this new implementation is added to use psycopg2.extras.execute_batch() instead of executemany when you initialize your engine with use_batch_mode=True like:

    engine = create_engine(
        "postgresql+psycopg2://scott:tiger@host/dbname",
        use_batch_mode=True)
    

    http://docs.sqlalchemy.org/en/latest/changelog/migration_12.html#change-4109

    Then someone would have to use SQLalchmey won't bother to try different combinations of sqla and psycopg2 and direct SQL together..

    0 讨论(0)
  • 2020-11-22 09:53

    If you're using SQLAlchemy, you don't need to mess with hand-crafting the string because SQLAlchemy supports generating a multi-row VALUES clause for a single INSERT statement:

    rows = []
    for i, name in enumerate(rawdata):
        row = {
            'id': i,
            'name': name,
            'valid': True,
        }
        rows.append(row)
    if len(rows) > 0:  # INSERT fails if no rows
        insert_query = SQLAlchemyModelName.__table__.insert().values(rows)
        session.execute(insert_query)
    
    0 讨论(0)
  • 2020-11-22 09:54

    New execute_values method in Psycopg 2.7:

    data = [(1,'x'), (2,'y')]
    insert_query = 'insert into t (a, b) values %s'
    psycopg2.extras.execute_values (
        cursor, insert_query, data, template=None, page_size=100
    )
    

    The pythonic way of doing it in Psycopg 2.6:

    data = [(1,'x'), (2,'y')]
    records_list_template = ','.join(['%s'] * len(data))
    insert_query = 'insert into t (a, b) values {}'.format(records_list_template)
    cursor.execute(insert_query, data)
    

    Explanation: If the data to be inserted is given as a list of tuples like in

    data = [(1,'x'), (2,'y')]
    

    then it is already in the exact required format as

    1. the values syntax of the insert clause expects a list of records as in

      insert into t (a, b) values (1, 'x'),(2, 'y')

    2. Psycopg adapts a Python tuple to a Postgresql record.

    The only necessary work is to provide a records list template to be filled by psycopg

    # We use the data list to be sure of the template length
    records_list_template = ','.join(['%s'] * len(data))
    

    and place it in the insert query

    insert_query = 'insert into t (a, b) values {}'.format(records_list_template)
    

    Printing the insert_query outputs

    insert into t (a, b) values %s,%s
    

    Now to the usual Psycopg arguments substitution

    cursor.execute(insert_query, data)
    

    Or just testing what will be sent to the server

    print (cursor.mogrify(insert_query, data).decode('utf8'))
    

    Output:

    insert into t (a, b) values (1, 'x'),(2, 'y')
    
    0 讨论(0)
  • 2020-11-22 09:54

    Using aiopg - The snippet below works perfectly fine

        # items = [10, 11, 12, 13]
        # group = 1
        tup = [(gid, pid) for pid in items]
        args_str = ",".join([str(s) for s in tup])
        # insert into group values (1, 10), (1, 11), (1, 12), (1, 13)
        yield from cur.execute("INSERT INTO group VALUES " + args_str)
    
    0 讨论(0)
提交回复
热议问题