SQLite Birincil Anahtar ekle


100

Sqlite'da CREATE TABLE ASbir tabloya dayalı bir tablo oluşturmak için sözdizimini kullanarak bir tablo oluşturdum.SELECT ifadeye . Şimdi bu tablonun birincil anahtarı yok, ancak bir tane eklemek istiyorum.

Yürütme ALTER TABLE table_name ADD PRIMARY KEY(col1, col2,...)"PRIMARY civarında" sözdizimi hatası veriyor

Sqlite'da tablo oluşturma sırasında veya sonrasında birincil anahtar eklemenin bir yolu var mı?

"Yaratılış sırasında" derken, ile yaratma sırasında demek istiyorum CREATE TABLE AS.


1
veritabanını düzenlemek için herhangi bir db tarayıcıyı kullanabilirsiniz. Ayrıca tabloları siliyor ve oluşturuyorlar. ama bununla uğraşmak istemiyoruz. herhangi bir işletim sistemi için db tarayıcısını buradan indirebilirsiniz sqlitebrowser.org
vichu

Yanıtlar:


122

Oluşturulduktan sonra SQLite tablolarını önemli bir şekilde değiştiremezsiniz. Kabul edilen önerilen çözüm, doğru gereksinimleri içeren yeni bir tablo oluşturmak ve verilerinizi buna kopyalayıp eski tabloyu bırakmaktır.

işte bununla ilgili resmi belgeler: http://sqlite.org/faq.html#q11


7
Bu bağlantı ( sqlite.org/omitted.html ) neyin ihmal edildiğini daha ayrıntılı olarak açıklamaktadır.
Martin Velez

1
ancak yeni sütunlar ekleyebiliriz
umesh


1
Bu tablo oluşturulduktan sonra bir PK ekleyemezsiniz ancak bir dizin ekleyebileceğiniz garip ( CREATE UNIQUE INDEX pkName ON tableName(columnName)) ne zaman DB gibi çerçeveler MS SQL en SMO aslında yapmak tablo oluşturulduktan sonra bir PK ekleyin!
SteveCinq

@deFreitas Lütfen bilgeliğinizi bize ihsan edin. Açıkça, insanların, yorum yapanlardan birinin söylediği yanıtı veya bir şeyi onaylamadığınızı bilmesini istiyorsunuz, ancak yorumunuz, üstünlük ve alay konusu ifade etme niyetinin yanı sıra hiçbir bilgi içermiyor.
Nathan Ridley

31

Kullandığınız sürece CREATE TABLE, birincil anahtarı tek bir alanda oluşturuyorsanız , şunları kullanabilirsiniz:

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

İle CREATE TABLE, bir veya daha fazla alanda birincil anahtar oluşturmak için her zaman aşağıdaki yaklaşımı kullanabilirsiniz :

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

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

Bu cevap, tablo değişikliğine değinmez.


10

Daha sonra sqlite_master tablosunu doğrudan değiştirerek birincil anahtarı eklemeye çalıştım. Bu numara işe yarıyor gibi görünüyor. Elbette bir hack çözümüdür.

Kısaca: Tabloda düzenli (benzersiz) bir dizin oluşturun, ardından şemayı yazılabilir yapın ve birincil anahtar dizinini tanımlamak için dizinin adını sqlite tarafından ayrılmış biçime değiştirin (yani, sqlite_autoindex_XXX_1, burada XXX tablo adıdır) ve sql dizesini NULL olarak ayarlayın. Sonunda tablo tanımının kendisini değiştirin. Bir pittfal: sqlite, veritabanı yeniden açılana kadar dizin adı değişikliğini görmez. Bu bir hata gibi görünüyor, ancak ciddi bir sorun değil (veritabanını yeniden açmadan bile kullanabilirsiniz).

Tablonun şöyle göründüğünü varsayalım:

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

Sonra şunu yaptım:

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;

Bazı testler (sqlite kabukta):

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
Bunu yanlış yaparsanız (söyleyebileceğim kadarıyla) tüm veritabanınızı erişilemez hale getirebileceğiniz konusunda bir uyarı. Etrafta oynuyordum ve yanlışlıkla ikinci güncelleme sorgusundaki WHERE cümlesini kaçırdım. SQLite bundan hoşlanmadı: P
Andrew Magee

7

Tablo oluşturma ile ilgili sqlite belgelerine göre , create table'i select olarak kullanmak, kısıtlamalar olmadan ve birincil anahtarsız yeni bir tablo oluşturur.

Bununla birlikte, dokümantasyon ayrıca birincil anahtarların ve benzersiz dizinlerin mantıksal olarak eşdeğer olduğunu söylüyor ( kısıtlamalar bölümüne bakın ):

Çoğu durumda, UNIQUE ve PRIMARY KEY kısıtlamaları, veritabanında benzersiz bir dizin oluşturarak uygulanır. (INTEGER PRIMARY KEY ve PRIMARY KEY dışında ROWID tablolarının istisnaları vardır.) Bu nedenle, aşağıdaki şemalar mantıksal olarak eşdeğerdir:

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

Bu nedenle, tablo tanımınızı SQL sözdizimini değiştirerek değiştiremezseniz bile, benzersiz bir dizin kullanarak aynı birincil anahtar etkisini elde edebilirsiniz.

Ayrıca, herhangi bir tablo (rowid sözdizimi olmadan oluşturulanlar dışında) "rowid" olarak bilinen bir iç tamsayı sütununa sahiptir. Dokümanlara göre, bu iç sütunu kayıt tablolarını almak / değiştirmek için kullanabilirsiniz.


Veritabanınıza bağlanmak için EntityFramework kullanıyorsanız, benzersiz bir dizini birincil anahtar olarak tanımaz. Dolayısıyla mantıksal ve işlevsel olarak SQLite içinde eşdeğer olsa da, her yerde tam olarak eşdeğer değildir.
Kristen Hammack

5

Bunu şu şekilde yapabilirsiniz:

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

3

Giriş

Bu, Android'in java'sına dayanmaktadır ve uygulama hayranlarınızı / müşterilerinizi rahatsız etmeden veritabanını değiştirmeye iyi bir örnektir. Bu, http://sqlite.org/faq.html#q11 SQLite SSS sayfası fikrine dayanmaktadır.

Sorun

Bir makbuzda satın alınan tek bir öğeyi silmek için bir row_number veya record_id ayarlamam gerektiğini fark etmedim ve aynı zamanda öğenin barkod numarası, bu öğeyi silmek için anahtar olarak yapmayı düşünmem için beni kandırdı. Makbuz_barcode tablosuna bir fiş ayrıntılarını kaydediyorum. Kayıt kimliği olmadan bırakmak, kalem barkodunu anahtar olarak kullandıysam bir makbuzdaki aynı öğenin tüm kayıtlarını silmek anlamına gelebilir.

Farkına varmak

Lütfen bunun, bu yazının yazıldığı sırada üzerinde çalıştığım kodumun bir kopyası-yapıştırılması olduğunu anlayın. Sadece örnek olarak kullanın, rastgele kopyalayıp yapıştırmak size yardımcı olmaz. Önce bunu ihtiyaçlarınıza göre değiştirin

Ayrıca lütfen koddaki yorumları okumayı unutmayın.

Kod

1. eklemek istediğiniz sütunun eksik olup olmadığını kontrol etmek için sınıfınızda bunu bir yöntem olarak kullanın. Bunu sadece makbuz_barcode tablosunu değiştirme işlemini tekrarlamamak için yapıyoruz. Sadece sınıfınızın bir parçası olarak bahsedin. Bir sonraki adımda onu nasıl kullanacağımızı göreceksiniz.

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

Ardından, aşağıdaki kod zaten eğer masa receipt_barcode oluşturmak için kullanılır DEĞİL uygulamanızın 1 kez kullananlar için çıkın. Ve lütfen kodda "MEVCUT DEĞİLSE" ifadesine dikkat edin. Önemi vardır.

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

Aynı sorunu yaşadım ve bulduğum en iyi çözüm, önce birincil anahtarı tanımlayan tabloyu oluşturmak ve ardından insert into statement kullanmaktır.

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

INSERT INTO mytable 
SELECT field1, field2 
FROM anothertable;

toplu ekler için kötü bir fikir
PirateApp

0

Birkaç sütunu birleştirmek için CREATE TABLE AS sözdizimini kullandım ve aynı sorunla karşılaştım. İşlemi hızlandırmak için yazdığım bir AppleScript.

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

Bence bu sütuna bir dizin eklemek hemen hemen aynı etkiyi sağlayabilir.


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

SQLite için DB Browser gibi bir araç kullanın, tabloya sağ tıklayarak basitçe PK, AI eklemeye izin verir -> değiştir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.