2009-06-03 25 views
86

Creé una tabla en Sqlite usando la sintaxis CREATE TABLE AS para crear una tabla basada en una declaración SELECT. Ahora esta tabla no tiene clave principal, pero me gustaría agregar una.SQLite add Primary Key

Ejecución ALTER TABLE table_name ADD PRIMARY KEY(col1, col2,...) da un error de sintaxis "cerca PRIMARIA"

¿Hay una manera de agregar una clave principal o bien durante la creación de la tabla o después en SQLite?

EDITAR: Por "durante la creación" quiero decir durante la creación con CREATE TABLE AS.

+0

puede utilizar cualquier navegador db para editar la base de datos. También están borrando y creando las tablas. pero no queremos molestarnos con eso. puede descargar el navegador db para cualquier sistema operativo desde aquí http://sqlitebrowser.org/ – vichu

Respuesta

110

No puede modificar las tablas de SQLite de forma significativa después de que se haya creado. La solución sugerida es crear una nueva tabla con los requisitos correctos y copiar sus datos en ella, luego soltar la tabla anterior.

aquí es la documentación oficial sobre esto: http://sqlite.org/faq.html#q11

+5

Este enlace (http://www.sqlite.org/omitted.html) explica lo que se omitió con más detalle. –

+1

pero podemos agregar nuevas columnas – umesh

+0

@umesh http://stackoverflow.com/questions/4253804/insert-new-column-into-table-in-sqlite –

5

Usted puede hacerlo de esta manera:

CREATE TABLE mytable (
field1 text, 
field2 text, 
field3 integer, 
PRIMARY KEY (field1, field2) 
); 
29

Mientras usted está utilizando CREATE TABLE, si va a crear la clave principal en una solo campo, puede utilizar:

CREATE TABLE mytable (
field1 TEXT, 
field2 INTEGER PRIMARY KEY, 
field3 BLOB, 
); 

Con CREATE TABLE, también puede usar siempre el siguiente enfoque para crear una clave principal en uno o campos múltiples:

CREATE TABLE mytable (
field1 TEXT, 
field2 INTEGER, 
field3 BLOB, 
PRIMARY KEY (field2, field1) 
); 

Referencia: http://www.sqlite.org/lang_createtable.html

Esta respuesta no se refiere a la alteración de mesa.

0

Utilicé la sintaxis CREATE TABLE AS para unir varias columnas y encontré el mismo problema. Aquí hay un AppleScript que escribí para acelerar el proceso.

set databasePath to "~/Documents/Databases/example.db" 
set tableOne to "separate" -- Table from which you are pulling data 
set tableTwo to "merged" -- Table you are creating 
set {tempCol, tempColEntry, permColEntry} to {{}, {}, {}} 
set permCol to {"id integer primary key"} 

-- Columns are created from single items AND from the last item of a list 
-- {{"a", "b", "c"}, "d", "e"} Columns "a" and "b" will be merged into a new column "c". tableTwo will have columns "c", "d", "e" 

set nonCoal to {"City", "Contact", "Names", {"Address 1", "Address", "address one", "Address1", "Text4", "Address 1"}, {"E-Mail", "E-Mail Address", "Email", "Email Address", "EmailAddress", "Email"}, {"Zip", "Zip Code", "ZipCode", "Zip"}, {"Telephone", "BusinessPhone", "Phone", "Work Phone", "Telephone"}, {"St", "State", "State"}, {"Salutation", "Mr/Ms", "Mr/s", "Salutations", "Sautation", "Salutation"}} 

-- Build the COALESCE statements 
repeat with h from 1 to count of nonCoal 
set aColumn to item h of nonCoal 
if class of aColumn is not list then 
    if (count of words of aColumn) > 1 then set aColumn to quote & aColumn & quote 
    set end of tempCol to aColumn 
    set end of permCol to aColumn 
else 
    set coalEntry to {} 
    repeat with i from 1 to count of aColumn 
     set coalCol to item i of aColumn as string 
     if (count of words of coalCol) > 1 then set coalCol to quote & coalCol & quote 
     if i = 1 then 
      set end of coalEntry to "TRIM(COALESCE(" & coalCol & ", '') || \" \" || " 
     else if i < ((count of aColumn) - 1) then 
      set end of coalEntry to "COALESCE(" & coalCol & ", '') || \" \" || " 
     else if i = ((count of aColumn) - 1) then 
      set as_Col to item (i + 1) of aColumn as string 
      if (count of words of as_Col) > 1 then set as_Col to quote & as_Col & quote 
      set end of coalEntry to ("COALESCE(" & coalCol & ", '')) AS " & as_Col) & "" 
      set end of permCol to as_Col 
     end if 
    end repeat 
    set end of tempCol to (coalEntry as string) 
end if 
end repeat 

-- Since there are ", '' within the COALESCE statement, you can't use "TID" and "as string" to convert tempCol and permCol for entry into sqlite3. I rebuild the lists in the next block. 
repeat with j from 1 to count of tempCol 
if j < (count of tempCol) then 
    set end of tempColEntry to item j of tempCol & ", " 
    set end of permColEntry to item j of permCol & ", " 
else 
    set end of tempColEntry to item j of tempCol 
    set end of permColEntry to item j of permCol 
end if 
end repeat 
set end of permColEntry to ", " & item (j + 1) of permCol 
set permColEntry to (permColEntry as string) 
set tempColEntry to (tempColEntry as string) 

-- Create the new table with an "id integer primary key" column 
set createTable to "create table " & tableTwo & " (" & permColEntry & "); " 
do shell script "sqlite3 " & databasePath & space & quoted form of createTable 

-- Create a temporary table and then populate the permanent table 
set createTemp to "create temp table placeholder as select " & tempColEntry & " from " & tableOne & "; " & "insert into " & tableTwo & " select Null, * from placeholder;" 
do shell script "sqlite3 " & databasePath & space & quoted form of createTemp 

--export the new table as a .csv file 
do shell script "sqlite3 -header -column -csv " & databasePath & " \"select * from " & tableTwo & " ; \"> ~/" & tableTwo & ".csv" 
9

Intenté agregar la clave primaria luego cambiando la tabla sqlite_master directamente. Este truco parece funcionar. Es una solución de pirateo, por supuesto.

En resumen: cree un índice regular (único) en la tabla, luego haga que el esquema sea modificable y cambie el nombre del índice a la forma reservada por sqlite para identificar un índice de clave principal (es decir, sqlite_autoindex_XXX_1, donde XXX es el nombre de la tabla) y establece la cadena sql en NULL. Por fin cambiar la definición de la tabla en sí. One pittfal: sqlite no ve el cambio en el nombre del índice hasta que se vuelva a abrir la base de datos. Esto parece un error, pero no grave (incluso sin volver a abrir la base de datos, todavía puede usarlo).

Supongamos que la tabla se ve así:

CREATE TABLE tab1(i INTEGER, j INTEGER, t TEXT); 

Entonces hice lo siguiente:

BEGIN; 
CREATE INDEX pk_tab1 ON tab1(i,j); 
pragma writable_schema=1; 
UPDATE sqlite_master SET name='sqlite_autoindex_tab1_1',sql=null WHERE name='pk_tab1'; 
UPDATE sqlite_master SET sql='CREATE TABLE tab1(i integer,j integer,t text,primary key(i,j))' WHERE name='tab1'; 
COMMIT; 

Algunas pruebas (con cáscara sqlite):

sqlite> explain query plan select * from tab1 order by i,j; 
0|0|0|SCAN TABLE tab1 USING INDEX sqlite_autoindex_tab1_1 
sqlite> drop index sqlite_autoindex_tab1_1; 
Error: index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped  
+1

+1 hack pero funciona! –

+1

Solo una advertencia de que puede (por lo que puedo decir) hacer que toda su base de datos sea inaccesible si lo hace mal. Estaba jugando y accidentalmente me perdí la cláusula WHERE en la segunda consulta de actualización. A SQLite no le gustó eso: P –

2

Introducción

Esto se basa en Java de Android y es un buen ejemplo de cómo cambiar la base de datos sin molestar a los fanáticos/clientes de la aplicación. Esto se basa en la idea de la página SQLite FAQ http://sqlite.org/faq.html#q11

El problema

No me di cuenta de que tengo que configurar un row_number o record_id para eliminar un solo artículo comprado en un recibo, y por lo Al mismo tiempo, el número de código de barras del artículo me engañó y me hizo pensar que sería la clave para eliminar ese artículo. Estoy guardando los detalles de un recibo en la tabla código de barra de recibo. Dejarlo sin un record_id puede significar borrar todos los registros del mismo ítem en un recibo si utilicé el código de barras del ítem como la clave.

Aviso

Por favor, entienda que este es un copiar y pegar de mi código Soy trabajar en en el momento de escribir estas líneas. Úselo solo como ejemplo, copiar y pegar al azar no lo ayudará. Modifique esto primero según sus necesidades

Además, no se olvide de leer los comentarios en el código.

El Código

utilizar esto como un método en su clase para comprobar primero si la columna que desea agregar no se encuentra. Hacemos esto solo para no repetir el proceso de alterar la tabla receipt_barcode. Solo menciónelo como parte de su clase. En el siguiente paso, verá cómo lo usaremos.

public boolean is_column_exists(SQLiteDatabase mDatabase , String table_name, 
String  column_name) { 
    //checks if table_name has column_name 
    Cursor cursor = mDatabase.rawQuery("pragma table_info("+table_name+")",null); 
    while (cursor.moveToNext()){ 
    if (cursor.getString(cursor.getColumnIndex("name")).equalsIgnoreCase(column_name)) return true; 
    } 
    return false; 
} 

A continuación, el siguiente código se utiliza para crear la receipt_barcode tabla si ya lo hace NO salida para la 1ª vez que los usuarios de su aplicación. Y tenga en cuenta el "SI NO EXISTE" en el código. Tiene importancia.

//mDatabase should be defined as a Class member (global variable) 
//for ease of access : 
//SQLiteDatabse mDatabase=SQLiteDatabase.openOrCreateDatabase(dbfile_path, null); 
creation_query = " CREATE TABLE if not exists receipt_barcode ("; 
creation_query += "\n record_id  INTEGER PRIMARY KEY AUTOINCREMENT,"; 
creation_query += "\n rcpt_id INT(11)  NOT NULL,"; 
creation_query += "\n barcode VARCHAR(255) NOT NULL ,"; 
creation_query += "\n barcode_price VARCHAR(255) DEFAULT (0),"; 
creation_query += "\n PRIMARY KEY (record_id));"; 
mDatabase.execSQL(creation_query); 

//This is where the important part comes in regarding the question in this page: 

//adding the missing primary key record_id in table receipt_barcode for older versions 
     if (!is_column_exists(mDatabase, "receipt_barcode","record_id")){ 
      mDatabase.beginTransaction(); 
      try{ 
       Log.e("record_id", "creating"); 


       creation_query="CREATE TEMPORARY TABLE t1_backup("; 
       creation_query+="record_id INTEGER  PRIMARY KEY AUTOINCREMENT,"; 
       creation_query+="rcpt_id INT(11)  NOT NULL,"; 
       creation_query+="barcode VARCHAR(255) NOT NULL ,"; 
       creation_query+="barcode_price VARCHAR(255) NOT NULL DEFAULT (0));"; 
       mDatabase.execSQL(creation_query); 

       creation_query="INSERT INTO t1_backup(rcpt_id,barcode,barcode_price) SELECT rcpt_id,barcode,barcode_price FROM receipt_barcode;"; 
       mDatabase.execSQL(creation_query); 

       creation_query="DROP TABLE receipt_barcode;"; 
       mDatabase.execSQL(creation_query); 

       creation_query="CREATE TABLE receipt_barcode ("; 
       creation_query+="record_id INTEGER  PRIMARY KEY AUTOINCREMENT,"; 
       creation_query+="rcpt_id INT(11)  NOT NULL,"; 
       creation_query+="barcode VARCHAR(255) NOT NULL ,"; 
       creation_query+="barcode_price VARCHAR(255) NOT NULL DEFAULT (0));"; 
       mDatabase.execSQL(creation_query); 

       creation_query="INSERT INTO receipt_barcode(record_id,rcpt_id,barcode,barcode_price) SELECT record_id,rcpt_id,barcode,barcode_price FROM t1_backup;"; 
       mDatabase.execSQL(creation_query); 

       creation_query="DROP TABLE t1_backup;"; 
       mDatabase.execSQL(creation_query); 


       mdb.setTransactionSuccessful(); 
      } catch (Exception exception){ 
       Log.e("table receipt_bracode", "Table receipt_barcode did not get a primary key (record_id"); 
       exception.printStackTrace(); 
      } finally { 
       mDatabase.endTransaction(); 
      } 
-1

Creo que agregar un índice en esa columna puede tener el mismo efecto.

0

Tuve el mismo problema y la mejor solución que encontré es crear primero la tabla que define la clave principal y luego usar insert into statement.

CREATE TABLE mytable (
field1 INTEGER PRIMARY KEY, 
field2 TEXT 
); 

INSERT INTO mytable 
SELECT field1, field2 
FROM anothertable; 
5

De acuerdo con el sqlite docs sobre creación de la tabla, utilizando el create table as select produce una nueva tabla sin restricciones y sin la clave principal.

Sin embargo, la documentación también dice que las claves primarias e índices únicos son lógicamente equivalentes (see constraints section):

En la mayoría de los casos, único y restricciones PRIMARY KEY se implementan mediante la creación de un índice único en la base de datos. (Las excepciones son INTEGER PRIMARY KEY y claves primarias sin tablas ROWID.) Por lo tanto, los siguientes esquemas son lógicamente equivalentes:

CREATE TABLE t1(a, b UNIQUE); 

CREATE TABLE t1(a, b PRIMARY KEY); 

CREATE TABLE t1(a, b); 
CREATE UNIQUE INDEX t1b ON t1(b); 

Por lo tanto, incluso si usted no puede modificar su definición de la tabla a través de SQL alter sintaxis, puede obtener el mismo efecto de clave principal a través del uso de un índice único.

Además, cualquier tabla (excepto las creadas sin la sintaxis rowid) tiene una columna entera interna conocida como "rowid". De acuerdo con los documentos, puede usar esta columna interna para recuperar/modificar tablas de registros.

0
sqlite> create table t(id int, col2 varchar(32), col3 varchar(8)); 
sqlite> insert into t values(1, 'he', 'ha'); 
sqlite> 
sqlite> create table t2(id int primary key, col2 varchar(32), col3 varchar(8)); 
sqlite> insert into t2 select * from t; 
sqlite> .schema 
CREATE TABLE t(id int, col2 varchar(32), col3 varchar(8)); 
CREATE TABLE t2(id int primary key, col2 varchar(32), col3 varchar(8)); 
sqlite> drop table t; 
sqlite> alter table t2 rename to t; 
sqlite> .schema 
CREATE TABLE IF NOT EXISTS "t"(id int primary key, col2 varchar(32), col3 varchar(8)); 
sqlite> 
Cuestiones relacionadas