Python Sqlite3: INSERT INTO table VALUE(dictionary goes here)

后端 未结 9 519
野趣味
野趣味 2020-12-24 12:26

I would like to use a dictionary to insert values into a table, how would I do this?

import sqlite3

db = sqlite3.connect(\'local.db\')
cur = db.cursor()

c         


        
相关标签:
9条回答
  • 2020-12-24 12:29

    You could use named parameters:

    cur.execute('INSERT INTO Media VALUES (NULL, :title, :type, :genre, :onchapter, :chapters, :status)', values)
    

    This still depends on the column order in the INSERT statement (those : are only used as keys in the values dict) but it at least gets away from having to order the values on the python side, plus you can have other things in values that are ignored here; if you're pulling what's in the dict apart to store it in multiple tables, that can be useful.

    If you still want to avoid duplicating the names, you could extract them from an sqlite3.Row result object, or from cur.description, after doing a dummy query; it may be saner to keep them around in python form near wherever you do your CREATE TABLE.

    0 讨论(0)
  • 2020-12-24 12:29

    I was having a similar problem and ended up with something not entirely unlike the following (Note - this is the OP's code with bits changed so that it works in the way they requested)-

    import sqlite3
    db = sqlite3.connect('local.db')
    cur = db.cursor()
    
    cur.execute('DROP TABLE IF EXISTS Media')
    
    cur.execute('''CREATE TABLE IF NOT EXISTS Media(
                    id INTEGER PRIMARY KEY, title TEXT, 
                    type TEXT,  genre TEXT,
                    onchapter INTEGER,  chapters INTEGER,
                    status TEXT
                    )''')
    
    
    values = {'title':'jack', 'type':None, 'genre':'Action',     'onchapter':None,'chapters':6,'status':'Ongoing'}
    
    #What would I Replace x with to allow a 
    #dictionary to connect to the values? 
    #cur.execute('INSERT INTO Media VALUES (NULL, x)'), values)
    # Added code.
    cur.execute('SELECT * FROM Media')
    colnames = cur.description
    list = [row[0] for row in cur.description]
    new_list = [values[i] for i in list if i in values.keys()]
    sql = "INSERT INTO Media VALUES ( NULL, "
    qmarks = ', '.join('?' * len(values))
    sql += qmarks + ")"
    cur.execute(sql, new_list)
    #db.commit() #<-Might be important.
    cur.execute('SELECT * FROM Media')
    media = cur.fetchone()
    print (media)
    
    0 讨论(0)
  • 2020-12-24 12:31

    Here's a more generic way with the benefit of escaping:

    # One way. If keys can be corrupted don't use.
    sql = 'INSERT INTO demo ({}) VALUES ({})'.format(
                ','.join(my_dict.keys()),
                ','.join(['?']*len(my_dict)))
    
    # Another, better way. Hardcoded w/ your keys.
    sql = 'INSERT INTO demo ({}) VALUES ({})'.format(
                ','.join(my_keys),
                ','.join(['?']*len(my_dict)))
    
    cur.execute(sql, tuple(my_dict.values()))
    
    0 讨论(0)
  • 2020-12-24 12:35

    Super late to this, but figured I would add my own answer. Not an expert, but something I found that works.

    There are issues with preserving order when using a dictionary, which other users have stated, but you could do the following:

    # We're going to use a list of dictionaries, since that's what I'm having to use in my problem
    input_list = [{'a' : 1 , 'b' : 2 , 'c' : 3} , {'a' : 14 , 'b' : '' , 'c' : 43}]
    for i in input_list:
        # I recommend putting this inside a function, this way if this 
        # Evaluates to None at the end of the loop, you can exit without doing an insert
        if i :
            input_dict = i 
        else:
            input_dict = None
            continue
    # I am noting here that in my case, I know all columns will exist.
    # If you're not sure, you'll have to get all possible columns first.
    
    keylist = list(input_dict.keys())
    vallist = list(input_dict.values())
    
    query = 'INSERT INTO example (' +','.join( ['[' + i + ']' for i in keylist]) + ') VALUES (' + ','.join(['?' for i in vallist]) + ')'
    
    items_to_insert = list(tuple(x.get(i , '') for i in keylist) for x in input_list)
    # Making sure to preserve insert order. 
    
    conn = sqlite3.connect(':memory:')
    cur = conn.cursor()
    cur.executemany(query , items_to_insert)
    conn.commit()
    
    0 讨论(0)
  • 2020-12-24 12:37

    There is a solution for using dictionaries. First, the sql-statement

    INSERT INTO Media VALUES (NULL, 'x');
    

    would not work, as it assumes you are referring to all columns, in the order they are defined in the CREATE TABLE statement, as abarnert stated. (See SQLite INSERT.)

    Once you have fixed it by specifying the columns, you can use named placeholders to insert data. The advantage of this is that is safely escapes key-characters, so you do not have to worry. From the Python sqlite-documentation:

    values = {'title':'jack', 'type':None, 'genre':'Action', 'onchapter':None,'chapters':6,'status':'Ongoing'}
    cur.execute('INSERT INTO Media (id, title, type, onchapter, chapters, status) VALUES (:id, :title, :type, :onchapter, :chapters, :status);'), values)
    
    0 讨论(0)
  • 2020-12-24 12:37

    I was having the similar problem so I created a string first and then passed that string to execute command. It does take longer time to execute but mapping was perfect for me. Just a work around:

    create_string = "INSERT INTO datapath_rtg( Sr_no"
    for key in record_tab:
        create_string = create_string+ " ," + str(key)
    create_string = create_string+ ") VALUES("+ str(Sr_no) 
    for key in record_tab:
        create_string = create_string+ " ," + str(record_tab[key])
    create_string = create_string + ")"
    cursor.execute(create_string)
    

    By doing above thing I ensured that if my dict (record_tab) doesn't contain a particular field then the script wont throw out error and proper mapping can be done which is why I used dictionary at the first place.

    0 讨论(0)
提交回复
热议问题