[sqlite] SQLite 기본 키 추가

문을 CREATE TABLE AS기반으로 테이블을 만드는 구문을 사용하여 Sqlite에서 테이블을 만들었습니다 SELECT. 이제이 테이블에는 기본 키가 없지만 추가하고 싶습니다.

실행 ALTER TABLE table_name ADD PRIMARY KEY(col1, col2,...)하면 “near PRIMARY”구문 오류가 발생합니다.

테이블 생성 중 또는 나중에 Sqlite에서 기본 키를 추가하는 방법이 있습니까?

“창조 중”이란 CREATE TABLE AS.



답변

SQLite 테이블이 생성 된 후에는 중요한 방식으로 수정할 수 없습니다. 허용되는 권장 솔루션은 올바른 요구 사항으로 새 테이블을 만들고 데이터를 여기에 복사 한 다음 이전 테이블을 삭제하는 것입니다.

이에 대한 공식 문서는 다음과 같습니다. http://sqlite.org/faq.html#q11


답변

를 사용 CREATE TABLE하는 한 단일 필드 에 기본 키를 만드는 경우 다음을 사용할 수 있습니다.

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

을 사용하면 CREATE TABLE항상 다음 접근 방식을 사용하여 하나 또는 여러 필드 에 기본 키를 만들 수 있습니다 .

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

참조 : http://www.sqlite.org/lang_createtable.html

이 답변은 테이블 변경을 다루지 않습니다.


답변

나중에 sqlite_master 테이블을 직접 변경하여 기본 키를 추가하려고했습니다. 이 트릭은 효과가있는 것 같습니다. 물론 해킹 솔루션입니다.

요컨대 : 테이블에 일반 (고유) 인덱스를 만든 다음 스키마를 쓰기 가능하게 만들고 인덱스 이름을 sqlite가 예약 한 형식으로 변경하여 기본 키 인덱스를 식별합니다 (예 : sqlite_autoindex_XXX_1, 여기서 XXX는 테이블 이름). SQL 문자열을 NULL로 설정하십시오. 마침내 테이블 정의 자체를 변경하십시오. 한 가지 핵심 : sqlite는 데이터베이스가 다시 열릴 때까지 인덱스 이름 변경을 보지 않습니다. 버그처럼 보이지만 심각한 버그는 아닙니다 (데이터베이스를 다시 열지 않아도 사용할 수 있습니다).

테이블이 다음과 같다고 가정합니다.

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

그런 다음 다음을 수행했습니다.

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;

일부 테스트 (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    


답변

테이블 생성에 관한 sqlite 문서 에 따르면 create table을 select로 사용하면 제약 조건없이 기본 키없이 새 테이블이 생성됩니다.

그러나 문서에는 기본 키와 고유 인덱스가 논리적으로 동일하다고도 나와 있습니다 ( 제약 조건 섹션 참조 ).

대부분의 경우 UNIQUE 및 PRIMARY KEY 제약 조건은 데이터베이스에 고유 인덱스를 생성하여 구현됩니다. (예외는 WITHOUT ROWID 테이블의 INTEGER PRIMARY KEY 및 PRIMARY KEY입니다.) 따라서 다음 스키마는 논리적으로 동일합니다.

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

따라서 SQL alter 구문을 통해 테이블 ​​정의를 변경할 수 없더라도 고유 인덱스를 사용하여 동일한 기본 키 효과를 얻을 수 있습니다.

또한 모든 테이블 (rowid 구문없이 생성 된 테이블 제외)에는 “rowid”라는 내부 정수 열이 있습니다. 문서에 따르면이 내부 열을 사용하여 레코드 테이블을 검색 / 수정할 수 있습니다.


답변

다음과 같이 할 수 있습니다.

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


답변

소개

이것은 Android의 Java를 기반으로하며 애플리케이션 팬 / 고객을 괴롭히지 않고 데이터베이스를 변경하는 좋은 예입니다. 이것은 SQLite FAQ 페이지 http://sqlite.org/faq.html#q11 의 아이디어를 기반으로합니다
.

문제

영수증에서 구매 한 단일 항목을 삭제하려면 row_number 또는 record_id를 설정해야한다는 사실을 알지 못했으며, 동시에 항목 바코드 번호가 해당 항목을 삭제하는 열쇠로 만드는 생각에 속았습니다. 영수증 세부 정보를 영수증 바코드 테이블에 저장하고 있습니다. record_id없이 그대로두면 항목 바코드를 키로 사용하면 영수증에서 동일한 항목의 모든 레코드를 삭제할 수 있습니다.

주의

이것은이 글을 쓰는 시점에 제가 작업하고있는 제 코드의 복사-붙여 넣기라는 것을 이해하십시오. 예제로만 사용하십시오. 무작위로 복사하여 붙여 넣는 것은 도움이되지 않습니다. 필요에 따라 먼저 수정하십시오.

또한 코드의 주석을 읽는 것을 잊지 마십시오.

코드

이것을 클래스에서 방법으로 사용하여 추가하려는 열이 누락되었는지 먼저 확인하십시오. 우리는 영수증 바코드 테이블을 변경하는 과정을 반복하지 않기 위해 이렇게합니다. 수업의 일부로 언급하십시오. 다음 단계에서 우리가 어떻게 사용하는지 볼 것입니다.

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

그런 다음 앱을 처음 사용하는 사용자에게 이미 종료 되지 않은 경우 영수증 _ 바코드 테이블을 생성하는 데 다음 코드가 사용됩니다 . 그리고 코드에서 “IF NOT EXISTS”를 확인하십시오. 중요합니다.

//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();
            }


답변

나는 같은 문제가 있었고 내가 찾은 최고의 해결책은 먼저 기본 키를 정의하는 테이블을 만든 다음 insert into 문을 사용하는 것입니다.

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

INSERT INTO mytable
SELECT field1, field2
FROM anothertable;