2011-06-04 30 views
6

estoy insertando valores en mi mesa (de código Python) de la siguiente manera:inserción en la tabla SQLite con la columna única

cur.execute("insert into t(a, b, c) values (?, ?, ?)", (a, b, c)) 

Hay una unique constraint en la columna c. ¿Cuál es una forma común de insert si quiero cubrir el caso cuando estamos insertando un valor duplicado para la columna c?
Tengo algunas ideas

  1. seleccionar todo, desde t para enumerar y reactivas antes de insertar si el valor ya está presente
  2. bloque try-catch
  3. poco más sofisticada declaración sqlite

Cómo lo probarías?

gracias

Respuesta

11

Usted podría utilizar INSERT OR REPLACE para actualizar filas con una restricción única , o INSERT OR IGNORE ignorar insertos que estén en conflicto con una restricción única:

import sqlite3 

def insert_or_replace(): 
    # https://sqlite.org/lang_insert.html 
    connection=sqlite3.connect(':memory:') 
    cursor=connection.cursor() 
    cursor.execute('CREATE TABLE foo (bar INTEGER UNIQUE, baz INTEGER)') 
    cursor.execute('INSERT INTO foo (bar,baz) VALUES (?, ?)',(1,2)) 
    cursor.execute('INSERT OR REPLACE INTO foo (bar,baz) VALUES (?, ?)',(1,3)) 
    cursor.execute('SELECT * from foo') 
    data=cursor.fetchall() 
    print(data) 
    # [(1, 3)] 


def on_conflict(): 
    # https://sqlite.org/lang_insert.html 
    connection=sqlite3.connect(':memory:') 
    cursor=connection.cursor() 
    cursor.execute('CREATE TABLE foo (bar INTEGER UNIQUE, baz INTEGER)') 
    cursor.execute('INSERT INTO foo (bar,baz) VALUES (?, ?)',(1,2)) 
    cursor.execute('INSERT OR IGNORE INTO foo (bar,baz) VALUES (?, ?)',(1,3)) 
    cursor.execute('SELECT * from foo') 
    data=cursor.fetchall() 
    print(data) 
    # [(1, 2)]  

insert_or_replace() 
on_conflict() 

Estos comandos sqlite son probablemente más rápido que escribir código Python a hacer lo mismo, aunque a probar esta se podría utilizar el módulo de Python timeit para probar la velocidad de var implementaciones religiosas Por ejemplo, podría ejecutar

python -mtimeit -s'import test' 'test.insert_or_replace()' 

frente

python -mtimeit -s'import test' 'test.filter_nonunique_rows_in_Python()' 

frente

python -mtimeit -s'import test' 'test.insert_with_try_catch_blocks()' 
+0

Gracias. ¿Es esto más eficiente que probar en python como el punto 1? Para mi situación, 'insertar o ignorar' es ideal. – xralf

+1

@xralf: sqlite está escrito en C, por lo que permitir que sqlite realice el filtrado es más probable que escribir su propio código para hacer lo mismo en Python. (Incluso si el código Python fuera tan rápido como el código C, igual tendría que cargar toda la tabla en un objeto de Python ...) Sin embargo, como usted preguntó cómo probar esta afirmación, sugerí usar 'python -mtimeit ... '. – unutbu

1

Depende :)

Si sólo hay un dispositivo de inserción del 1 podría ser el más eficiente.

Si hay varios dispositivos de inserción que tiene que utilizar 2 como menos de 1 usted podría probar y parece bien, pero otra de inserción añade el valor C que tiene por lo que no

+0

Gracias, parece que sólo habrá un dispositivo de inserción (hasta ahora, se puede cambiar en el futuro). Lo tengo implementado como 1, pero es (esta prueba) bastante tipeo si quiero escribir un nuevo código de inserción y no estoy seguro de si es eficiente para probar, p. 10000 valores en la lista. Tal vez sqlite tiene algo más sofisticado con la definición de indeces. – xralf

Cuestiones relacionadas