SQLite adiciona chave primária


99

Criei uma tabela no Sqlite usando a CREATE TABLE ASsintaxe para criar uma tabela com base em uma SELECTinstrução. Agora, esta tabela não tem chave primária, mas gostaria de adicionar uma.

A execução ALTER TABLE table_name ADD PRIMARY KEY(col1, col2,...)dá um erro de sintaxe "próximo a PRIMARY"

Existe uma maneira de adicionar uma chave primária durante a criação da tabela ou posteriormente no Sqlite?

Por "durante a criação", quero dizer durante a criação com CREATE TABLE AS.


1
você pode usar qualquer navegador db para editar banco de dados. Eles também estão excluindo e criando as tabelas. mas não queremos nos preocupar com isso. você pode baixar o navegador db para qualquer sistema operacional aqui sqlitebrowser.org
vichu

Respostas:


121

Você não pode modificar as tabelas SQLite de nenhuma maneira significativa após terem sido criadas. A solução sugerida aceita é criar uma nova tabela com os requisitos corretos, copiar seus dados nela e, em seguida, eliminar a tabela antiga.

aqui está a documentação oficial sobre isso: http://sqlite.org/faq.html#q11


6
Este link ( sqlite.org/omitted.html ) explica o que foi omitido em mais detalhes.
Martin Velez

1
mas podemos adicionar novas colunas
umesh de


1
É estranho que você não possa adicionar um PK após a criação da tabela, mas você pode adicionar um índice ( CREATE UNIQUE INDEX pkName ON tableName(columnName)) quando estruturas de banco de dados como o SMO do MS SQL realmente fazem você adicionar um PK após a tabela ter sido criada!
SteveCinq

@deFreitas Por favor, conceda-nos sua sabedoria. Obviamente, você quer que as pessoas saibam que você desaprova a resposta ou algo que um dos comentadores disse, porém seu comentário não contém nenhuma informação, além de uma aparente intenção de transmitir superioridade e sarcasmo.
Nathan Ridley

31

Enquanto estiver usando CREATE TABLE, se estiver criando a chave primária em um único campo , você pode usar:

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

Com CREATE TABLE, você também pode sempre usar a seguinte abordagem para criar uma chave primária em um ou vários campos :

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

Referência: http://www.sqlite.org/lang_createtable.html

Esta resposta não aborda a alteração da tabela.


10

Tentei adicionar a chave primária posteriormente, alterando a tabela sqlite_master diretamente. Este truque parece funcionar. É uma solução de hack, claro.

Resumindo: crie um índice regular (único) na tabela, torne o esquema gravável e altere o nome do índice para a forma reservada por sqlite para identificar um índice de chave primária, (ou seja, sqlite_autoindex_XXX_1, onde XXX é o nome da tabela) e defina a string sql como NULL. Por fim, altere a própria definição da tabela. Um pittfal: sqlite não vê a mudança do nome do índice até que o banco de dados seja reaberto. Isso parece um bug, mas não é grave (mesmo sem reabrir o banco de dados, você ainda pode usá-lo).

Suponha que a tabela se pareça com:

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

Então eu fiz o seguinte:

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;

Alguns testes (no shell 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    

2
Apenas um aviso de que você pode (tanto quanto eu posso dizer) tornar seu banco de dados inteiro inacessível se você fizer isso errado. Eu estava brincando e acidentalmente perdi a cláusula WHERE na segunda consulta de atualização. SQLite não gostou disso: P
Andrew Magee

7

De acordo com a documentação do sqlite sobre a criação de tabelas, o uso de create table como select produz uma nova tabela sem restrições e sem chave primária.

No entanto, a documentação também diz que as chaves primárias e os índices exclusivos são logicamente equivalentes ( consulte a seção de restrições ):

Na maioria dos casos, as restrições UNIQUE e PRIMARY KEY são implementadas criando um índice exclusivo no banco de dados. (As exceções são INTEGER PRIMARY KEY e PRIMARY KEYs em tabelas WITHOUT ROWID.) Portanto, os seguintes esquemas são logicamente 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); 

Portanto, mesmo que não seja possível alterar a definição da tabela por meio da sintaxe de alteração do SQL, você pode obter o mesmo efeito de chave primária usando um índice exclusivo.

Além disso, qualquer tabela (exceto aquelas criadas sem a sintaxe rowid) tem uma coluna inteira interna conhecida como "rowid". De acordo com os documentos, você pode usar esta coluna interna para recuperar / modificar tabelas de registro.


Se você estiver usando EntityFramework para se conectar ao seu banco de dados, ele não reconhecerá um índice exclusivo como chave primária. Portanto, embora seja lógica e funcionalmente equivalente dentro do SQLite, não é totalmente equivalente em todos os lugares.
Kristen Hammack de

5

Você pode fazer assim:

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

3

Introdução

Ele é baseado em java do Android e é um bom exemplo de como alterar o banco de dados sem incomodar os fãs / clientes de seus aplicativos. Isso é baseado na ideia da página de perguntas frequentes do SQLite http://sqlite.org/faq.html#q11

O problema

Não percebi que preciso definir um row_number ou record_id para excluir um único item comprado em um recibo e, ao mesmo tempo, o número do código de barras do item me enganou ao pensar em torná-lo a chave para excluir aquele item. Estou salvando os detalhes de um recibo na tabela código_de_barras de recebimento. Deixá-lo sem um record_id pode significar a exclusão de todos os registros do mesmo item em um recibo se eu usar o código de barras do item como a chave.

Aviso prévio

Por favor, entenda que este é um copiar e colar do meu código no qual estou trabalhando no momento da redação deste artigo. Use-o apenas como um exemplo, copiar e colar aleatoriamente não o ajudará. Modifique primeiro de acordo com suas necessidades

Além disso, não se esqueça de ler os comentários no código.

O código

Use isso como um método em sua classe para verificar primeiro se a coluna que você deseja adicionar está faltando. Fazemos isso apenas para não repetir o processo de alteração do código_de_barras da tabela. Basta mencioná-lo como parte de sua aula. Na próxima etapa, você verá como o 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;
}

Em seguida, o código a seguir é usado para criar a tabela receive_barcode se ela já NÃO sair para os usuários da primeira vez de seu aplicativo. E observe o "SE NÃO EXISTE" no código. Tem importância.

//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

Eu tive o mesmo problema e a melhor solução que encontrei é primeiro criar a tabela que define a chave primária e então usar a instrução insert into.

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

INSERT INTO mytable 
SELECT field1, field2 
FROM anothertable;

má ideia para inserções em massa
PirateApp

0

Usei a sintaxe CREATE TABLE AS para mesclar várias colunas e encontrei o mesmo problema. Aqui está um AppleScript que escrevi para acelerar o processo.

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"

0

Acho que adicionar um índice nessa coluna pode ter praticamente o mesmo efeito.


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>

0

Use uma ferramenta como o DB Browser para SQLite, permite adicionar PK, AI simplesmente clicando com o botão direito na tabela -> modificar.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.