SQLite menambahkan Kunci Utama

100

Saya membuat tabel di Sqlite dengan menggunakan CREATE TABLE ASsintaks untuk membuat tabel berdasarkan SELECTpernyataan. Sekarang tabel ini tidak memiliki kunci utama tetapi saya ingin menambahkannya.

Eksekusi ALTER TABLE table_name ADD PRIMARY KEY(col1, col2,...)memberikan kesalahan sintaks "near PRIMARY"

Apakah ada cara untuk menambahkan kunci utama selama pembuatan tabel atau setelahnya di Sqlite?

Yang saya maksud dengan "selama penciptaan" adalah selama penciptaan dengan CREATE TABLE AS.

Jack Edmonds
sumber
1
Anda dapat menggunakan browser db apa pun untuk mengedit database. Mereka juga menghapus dan membuat tabel. tapi kami tidak ingin mempedulikannya. Anda dapat mengunduh db browser untuk OS apa pun dari sini sqlitebrowser.org
vichu

Jawaban:

122

Anda tidak dapat mengubah tabel SQLite dengan cara apa pun setelah dibuat. Solusi yang disarankan yang diterima adalah membuat tabel baru dengan persyaratan yang benar dan menyalin data Anda ke dalamnya, lalu melepaskan tabel lama.

berikut adalah dokumentasi resmi tentang ini: http://sqlite.org/faq.html#q11

Nathan Ridley
sumber
7
Tautan ini ( sqlite.org/omitted.html ) menjelaskan apa yang dihilangkan secara lebih detail.
Martin Velez
1
tapi kita bisa menambahkan kolom baru
umesh
1
Aneh bahwa Anda tidak dapat menambahkan PK setelah pembuatan tabel tetapi Anda dapat menambahkan indeks ( CREATE UNIQUE INDEX pkName ON tableName(columnName)) ketika kerangka kerja DB seperti SMO MS SQL benar - benar membuat Anda menambahkan PK setelah tabel dibuat!
SteveCinq
@deFreitas Tolong berikan kebijaksanaan Anda kepada kami. Jelas Anda ingin orang tahu Anda tidak setuju dengan jawaban atau sesuatu yang dikatakan salah satu pemberi komentar, namun komentar Anda tidak mengandung informasi sama sekali, di samping maksud yang jelas untuk menyampaikan superioritas dan kecaman.
Nathan Ridley
31

Selama Anda menggunakan CREATE TABLE, jika Anda membuat kunci utama pada satu bidang , Anda dapat menggunakan:

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

Dengan CREATE TABLE, Anda juga selalu dapat menggunakan pendekatan berikut untuk membuat kunci utama di satu atau beberapa bidang :

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

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

Jawaban ini tidak membahas perubahan tabel.

Acumenus
sumber
10

Saya mencoba menambahkan kunci utama setelah itu dengan mengubah tabel sqlite_master secara langsung. Trik ini sepertinya berhasil. Ini adalah solusi peretasan tentu saja.

Singkatnya: buat indeks reguler (unik) di atas tabel, kemudian buat skema dapat ditulis dan ubah nama indeks ke formulir yang disediakan oleh sqlite untuk mengidentifikasi indeks kunci utama, (yaitu sqlite_autoindex_XXX_1, dengan XXX adalah nama tabel) dan setel string sql ke NULL. Akhirnya ubah definisi tabel itu sendiri. Satu pittfal: sqlite tidak melihat perubahan nama indeks sampai database dibuka kembali. Ini sepertinya bug, tetapi bukan yang parah (bahkan tanpa membuka kembali database, Anda masih dapat menggunakannya).

Misalkan tabel terlihat seperti:

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

Kemudian saya melakukan hal berikut:

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;

Beberapa tes (dalam 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    
pengguna3098421
sumber
2
Hanya peringatan bahwa Anda dapat (sejauh yang saya tahu) membuat seluruh database Anda tidak dapat diakses jika Anda melakukan kesalahan ini. Saya sedang bermain-main dan saya tidak sengaja melewatkan klausa WHERE di kueri pembaruan kedua. SQLite tidak suka itu: P
Andrew Magee
7

Menurut dokumen sqlite tentang pembuatan tabel, menggunakan buat tabel sebagai pilih menghasilkan tabel baru tanpa batasan dan tanpa kunci utama.

Namun, dokumentasi juga mengatakan bahwa kunci utama dan indeks unik secara logis setara ( lihat bagian batasan ):

Dalam kebanyakan kasus, kendala UNIQUE dan PRIMARY KEY diimplementasikan dengan membuat indeks unik dalam database. (Pengecualiannya adalah INTEGER PRIMARY KEY dan PRIMARY KEY pada tabel TANPA ROWID.) Oleh karena itu, skema berikut secara logis setara:

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); 

Jadi, bahkan jika Anda tidak dapat mengubah definisi tabel melalui sintaks alter SQL, Anda bisa mendapatkan efek kunci utama yang sama melalui penggunaan indeks unik.

Selain itu, setiap tabel (kecuali yang dibuat tanpa sintaks rowid) memiliki kolom integer dalam yang dikenal sebagai "rowid". Menurut dokumen, Anda bisa menggunakan kolom dalam ini untuk mengambil / mengubah tabel rekaman.

Carlitos Way
sumber
Jika Anda menggunakan EntityFramework untuk menyambungkan ke database Anda, itu tidak mengenali indeks unik sebagai kunci utama. Jadi meskipun secara logis dan fungsional setara di dalam SQLite, itu tidak cukup setara di semua tempat.
Kristen Hammack
5

Anda bisa melakukannya seperti ini:

CREATE TABLE mytable (
field1 text,
field2 text,
field3 integer,
PRIMARY KEY (field1, field2)
);
Nick Dandoulakis
sumber
3

pengantar

Ini didasarkan pada Java Android dan ini adalah contoh yang baik untuk mengubah database tanpa mengganggu penggemar / pelanggan aplikasi Anda. Ini didasarkan pada ide halaman FAQ SQLite http://sqlite.org/faq.html#q11

Masalah

Saya tidak menyadari bahwa saya perlu menyetel row_number atau record_id untuk menghapus satu item yang dibeli dalam tanda terima, dan pada saat yang sama nomor barcode item menipu saya untuk berpikir menjadikannya sebagai kunci untuk menghapus item itu. Saya menyimpan detail tanda terima di tabel struk_barcode. Membiarkannya tanpa record_id bisa berarti menghapus semua record dari item yang sama dalam tanda terima jika saya menggunakan item barcode sebagai kuncinya.

Memperhatikan

Harap dipahami bahwa ini adalah salinan-tempel kode yang saya kerjakan pada saat penulisan ini. Gunakan hanya sebagai contoh, copy-paste secara acak tidak akan membantu Anda. Ubah ini terlebih dahulu sesuai kebutuhan Anda

Juga jangan lupa untuk membaca komentar di kode.

Kode

Gunakan ini sebagai metode di kelas Anda untuk memeriksa 1 apakah kolom yang ingin Anda tambahkan hilang. Kami melakukan ini hanya untuk tidak mengulangi proses mengubah kode tabel tanda terima. Sebut saja sebagai bagian dari kelas Anda. Pada langkah selanjutnya Anda akan melihat bagaimana kami akan menggunakannya.

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;
}

Kemudian, kode berikut digunakan untuk membuat tabel tanda terima_barcode jika sudah TIDAK keluar untuk pengguna aplikasi Anda yang pertama kali. Dan harap perhatikan "JIKA TIDAK ADA" di kode. Itu penting.

//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();
            }
superlinux.dll
sumber
1

Saya memiliki masalah yang sama dan solusi terbaik yang saya temukan adalah pertama-tama membuat tabel yang mendefinisikan kunci utama dan kemudian menggunakan masukkan ke dalam pernyataan.

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

INSERT INTO mytable 
SELECT field1, field2 
FROM anothertable;
Spa
sumber
ide buruk untuk penyisipan massal
PirateApp
0

Saya menggunakan sintaks CREATE TABLE AS untuk menggabungkan beberapa kolom dan mengalami masalah yang sama. Ini adalah AppleScript yang saya tulis untuk mempercepat proses.

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"
adayzdone
sumber
0

Saya pikir menambahkan indeks pada kolom itu bisa mendapatkan efek yang hampir sama.

Qiulang
sumber
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>
sanshaoye
sumber
0

Gunakan alat seperti DB Browser untuk SQLite, ini memungkinkan untuk menambahkan PK, AI dengan mengklik kanan pada tabel -> ubah.

codeapply
sumber