Как установить первичный ключ в базе данных SQLite после того, как таблица уже создана? - PullRequest
1 голос
/ 03 июля 2019

Как установить первичный ключ в SQLite после того, как таблица уже создана?

Я создаю проект с использованием SQLite, и я забыл предоставить первичный ключ для идентификатора пользователя, теперь, как я могу его установить?

Ниже мой класс ContactContract

public final class ContactContract {

    private ContactContract(){}


    public static class ContactEntry
    {
        public static final String TABLE_NAME="contact_info";
        public static final String KEY_P = "KEY";
        public static final String CONTACT_ID = "contact_id";
        public static final String NAME="name";
        public static final String EMAIL="email";

    }
}

Ниже мой класс ContactDbHelper

public class ContactDbHelper extends SQLiteOpenHelper {

    public static final String DATABASE_NAME = "contact_db";
    public static final int DATABASE_VERSION = 1;

    public static final String CREATE_TABLE="create table "+ContactContract.ContactEntry.TABLE_NAME+
            "(" + ContactContract.ContactEntry.KEY_P +"INTEGER PRIMARY KEY," +ContactContract.ContactEntry.CONTACT_ID+" number,"+ContactContract.ContactEntry.NAME+" text,"+
            ContactContract.ContactEntry.EMAIL+" text);";

1 Ответ

0 голосов
/ 04 июля 2019

Использование: -

 public static final String CREATE_TABLE="create table "+ContactContract.ContactEntry.TABLE_NAME+
            "(" + ContactContract.ContactEntry.KEY_P +"INTEGER PRIMARY KEY," +ContactContract.ContactEntry.CONTACT_ID+" number,"+ContactContract.ContactEntry.NAME+" text,"+
            ContactContract.ContactEntry.EMAIL+" text);";

Не будет работать должным образом из-за: -

  1. У вас нет пробела после имени столбца и INTEGER PRIMARY KEY,,

    • имя столбца будет KEYINTEGER вместо KEY и, скорее всего, приведет к проблемам.
    • столбец не будет основнымключ и, следовательно, не будет автоматически генерировать полезный столбец, если значение столбца пропущено (как это часто бывает), значение будет нулевым.
  2. Вы не можете иметь столбецс именем KEY (как в случае добавления пробела перед INTEGER), поскольку это ключевое слово.Возможно, используйте public static final String KEY_P = "KEYP";, чтобы преодолеть это.

В качестве такого использования: -

public static final String KEY_P = "KEYP";
  • или что-то отличное от = "KEY", которое подходитне ключевое слово

вместе с: -

 public static final String CREATE_TABLE="create table "+ContactContract.ContactEntry.TABLE_NAME+
            "(" + ContactContract.ContactEntry.KEY_P +" INTEGER PRIMARY KEY," +ContactContract.ContactEntry.CONTACT_ID+" number,"+ContactContract.ContactEntry.NAME+" text,"+
            ContactContract.ContactEntry.EMAIL+" text);";

С 1 и 2 исправлено.Затем, если вы можете легко восстановить данные, вы можете переустановить приложение, чтобы применить изменения схемы.


Однако , поскольку вы заявляете, что база данных былаи если вы не можете легко восстановить данные, то это можно сделать.

Предполагая, что база данных в настоящее время содержит данные (например, для тестирования следующие данные являются частью): -

СледующееМожно использовать метод, чтобы изменить схему для добавления столбца PRIMARY KEY: -

private void addPrimaryKey() {
    String TAG = "ADDPRMRYKEY";
    Log.d(TAG,"Initiated adding the primary key.");
    SQLiteDatabase db = this.getWritableDatabase();
    Cursor csr = db.query(
            "sqlite_master",
            null,
            "name =? AND instr(sql,'PRIMARY KEY') > 0",
            new String[]{ContactContract.ContactEntry.TABLE_NAME},
            null,null,null
    );
    if (csr.getCount() < 1) {
        Log.d(TAG," PRIMARY KEY clause not found for table " + ContactContract.ContactEntry.TABLE_NAME);
        if (CREATE_TABLE.indexOf("PRIMARY KEY") > 0) {
            Log.d(TAG,"PRIMARY KEY clause located in CREATE TABLE SQL so !!!!ALTERING!!!! table " + ContactContract.ContactEntry.TABLE_NAME);
            db.execSQL("ALTER TABLE " + ContactContract.ContactEntry.TABLE_NAME + " RENAME TO OLD" + ContactContract.ContactEntry.TABLE_NAME);
            Log.d(TAG,"RENAMED TABLE " + ContactContract.ContactEntry.TABLE_NAME + " to OLD" + ContactContract.ContactEntry.TABLE_NAME);
            db.execSQL(CREATE_TABLE);
            Log.d(TAG,"CREATED new version of table " + ContactContract.ContactEntry.TABLE_NAME + " !!!!INSERTING DATA EXTRACTED!!!! from old version");
            db.execSQL("INSERT INTO " + ContactContract.ContactEntry.TABLE_NAME + " SELECT null,* FROM OLD" + ContactContract.ContactEntry.TABLE_NAME);
        } else {
            Log.d(TAG,"PRIMARY KEY clause not found in the CREATE TABLE SQL so doing nothing.");
        }
    } else {
        Log.d(TAG,"PRIMARY KEY clause found for table " + ContactContract.ContactEntry.TABLE_NAME + " - Nothing to do!!!!");
    }
    csr.close();
}
  • Обратите внимание, что операторы Log.d будут удалены, они использовались для тестирования / объяснения.

Вышеуказанное работает путем

  1. опроса таблицы sqlite_master для извлечения SQL, использованного для создания таблицы, ЕСЛИ она включает в себя предложение PRIMARY KEY.

  2. Если это так, метод возвращает результат, ничего не делая, так как PRIMARY KEY уже определен.

  3. Потенциально новая таблица / таблица замены создает SQLпроверяется, содержит ли оно условие PRIMARY KEY.

  4. Если этого не произойдет, то ничего не будет сделано.

  5. Текущая таблицаRENAMED.

  6. Новая таблица с исходным именем создается в соответствии с таблицей создания SQL.

  7. Данные копируются из исходной таблицык новой таблице.

    • Обратите внимание, что вы можете рассмотреть возможность удаления переименованной исходной таблицы.Он не был удален, так как безопаснее иметь его на всякий случай.

Вместо того, чтобы увеличивать номер версии, метод addPrimaryKey был включен в конструктор Помощника по базам данных какper: -

public ContactDbHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
    addPrimaryKey(); //<<<<<<<<<< ADDED to Convert
}
  • метод addPrimaryKey будет запускаться каждый раз, но он будет пытаться преобразовать данные только в том случае, если
    • таблица не имеетПредложение PRIMARY KEY и
    • CREATE SQL включает в себя предложение PRIMARY KEY
    • . Предполагается, что столбец PRIMARY KEY является первым определенным столбцом, в противном случае строка db.execSQL("INSERT INTO " + ContactContract.ContactEntry.TABLE_NAME + " SELECT null,* FROM OLD" + ContactContract.ContactEntry.TABLE_NAME); должна быть изменена.соответственно.

Тестирование

Настройка

Приложение было запущено с использованием (KEY_P закомментирован, поскольку предполагается текущий статус): -

public static final String CREATE_TABLE = "create table " + ContactContract.ContactEntry.TABLE_NAME +
        "(" +
        //ContactContract.ContactEntry.KEY_P + " INTEGER PRIMARY KEY," + //<<<<<<<<<< comment out this line for first run to generate data
        ContactContract.ContactEntry.CONTACT_ID + " number," +
        ContactContract.ContactEntry.NAME + " text," +
        ContactContract.ContactEntry.EMAIL + " text" +
        ");";

Активизирующая активность, использованная во всем:только если ничего не существует (100строк со случайно сгенерированными контактными данными), это просто для демонстрации того, что это работает.

Извлеките все строки, сбросив курсор в соответствии с

: -

2019-07-04 15:52:03.813 7758-7758/aso.so56873021recopydb D/ADDPRMRYKEY: Initiated adding the primary key.
2019-07-04 15:52:03.830 7758-7758/aso.so56873021recopydb D/ADDPRMRYKEY:  PRIMARY KEY clause not found for table contact_info
2019-07-04 15:52:03.830 7758-7758/aso.so56873021recopydb D/ADDPRMRYKEY: PRIMARY KEY clause not found in the CREATE TABLE SQL so doing nothing.
2019-07-04 15:52:03.888 7758-7758/aso.so56873021recopydb I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@791f7af
2019-07-04 15:52:03.890 7758-7758/aso.so56873021recopydb I/System.out: 0 {
2019-07-04 15:52:03.890 7758-7758/aso.so56873021recopydb I/System.out:    contact_id=-1179778271
2019-07-04 15:52:03.890 7758-7758/aso.so56873021recopydb I/System.out:    name=Aname0
2019-07-04 15:52:03.890 7758-7758/aso.so56873021recopydb I/System.out:    email=Aname0@email.com
2019-07-04 15:52:03.890 7758-7758/aso.so56873021recopydb I/System.out: }
2019-07-04 15:52:03.890 7758-7758/aso.so56873021recopydb I/System.out: 1 {
2019-07-04 15:52:03.890 7758-7758/aso.so56873021recopydb I/System.out:    contact_id=1334348157
2019-07-04 15:52:03.890 7758-7758/aso.so56873021recopydb I/System.out:    name=Aname1
2019-07-04 15:52:03.890 7758-7758/aso.so56873021recopydb I/System.out:    email=Aname1@email.com
2019-07-04 15:52:03.890 7758-7758/aso.so56873021recopydb I/System.out: }
2019-07-04 15:52:03.890 7758-7758/aso.so56873021recopydb I/System.out: 2 {
2019-07-04 15:52:03.891 7758-7758/aso.so56873021recopydb I/System.out:    contact_id=1123604651
2019-07-04 15:52:03.891 7758-7758/aso.so56873021recopydb I/System.out:    name=Aname2
2019-07-04 15:52:03.891 7758-7758/aso.so56873021recopydb I/System.out:    email=Aname2@email.com

Преобразование

Как видно из выходных данных выше, метод addPrimaryKey был вызван, но ничего не сделал из-за D/ADDPRMRYKEY: PRIMARY KEY clause not found in the CREATE TABLE SQL so doing nothing.

Таким образом, это просто вопрос изменения CREATE SQL для включенияновый столбец будет: -

public static final String CREATE_TABLE = "create table " + ContactContract.ContactEntry.TABLE_NAME +
        "(" +
        ContactContract.ContactEntry.KEY_P + " INTEGER PRIMARY KEY," + //<<<<<<<<<< comment out this line for first run to generate data
        ContactContract.ContactEntry.CONTACT_ID + " number," +
        ContactContract.ContactEntry.NAME + " text," +
        ContactContract.ContactEntry.EMAIL + " text" +
        ");";
  • т.е. столбец KEY_P больше не будет закомментирован, поэтому новый / требуемый SQL введен в игру.

Ирезультат согласно: -

2019-07-04 15:56:47.170 7979-7979/aso.so56873021recopydb D/ADDPRMRYKEY: Initiated adding the primary key.
2019-07-04 15:56:47.175 7979-7979/aso.so56873021recopydb D/ADDPRMRYKEY:  PRIMARY KEY clause not found for table contact_info
2019-07-04 15:56:47.176 7979-7979/aso.so56873021recopydb D/ADDPRMRYKEY: PRIMARY KEY clause located in CREATE TABLE SQL so !!!!ALTERING!!!! table contact_info
2019-07-04 15:56:47.176 7979-7979/aso.so56873021recopydb D/ADDPRMRYKEY: RENAMED TABLE contact_info to OLDcontact_info
2019-07-04 15:56:47.177 7979-7979/aso.so56873021recopydb D/ADDPRMRYKEY: CREATED new version of table contact_info !!!!INSERTING DATA EXTRACTED!!!! from old version
2019-07-04 15:56:47.179 7979-7979/aso.so56873021recopydb I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@791f7af
2019-07-04 15:56:47.179 7979-7979/aso.so56873021recopydb I/System.out: 0 {
2019-07-04 15:56:47.179 7979-7979/aso.so56873021recopydb I/System.out:    KEYP=1
2019-07-04 15:56:47.179 7979-7979/aso.so56873021recopydb I/System.out:    contact_id=-1179778271
2019-07-04 15:56:47.180 7979-7979/aso.so56873021recopydb I/System.out:    name=Aname0
2019-07-04 15:56:47.180 7979-7979/aso.so56873021recopydb I/System.out:    email=Aname0@email.com
2019-07-04 15:56:47.180 7979-7979/aso.so56873021recopydb I/System.out: }
2019-07-04 15:56:47.180 7979-7979/aso.so56873021recopydb I/System.out: 1 {
2019-07-04 15:56:47.180 7979-7979/aso.so56873021recopydb I/System.out:    KEYP=2
2019-07-04 15:56:47.180 7979-7979/aso.so56873021recopydb I/System.out:    contact_id=1334348157
2019-07-04 15:56:47.180 7979-7979/aso.so56873021recopydb I/System.out:    name=Aname1
2019-07-04 15:56:47.180 7979-7979/aso.so56873021recopydb I/System.out:    email=Aname1@email.com
2019-07-04 15:56:47.180 7979-7979/aso.so56873021recopydb I/System.out: }
2019-07-04 15:56:47.180 7979-7979/aso.so56873021recopydb I/System.out: 2 {
2019-07-04 15:56:47.180 7979-7979/aso.so56873021recopydb I/System.out:    KEYP=3
2019-07-04 15:56:47.180 7979-7979/aso.so56873021recopydb I/System.out:    contact_id=1123604651
2019-07-04 15:56:47.181 7979-7979/aso.so56873021recopydb I/System.out:    name=Aname2
2019-07-04 15:56:47.181 7979-7979/aso.so56873021recopydb I/System.out:    email=Aname2@email.com

т.е. данные были сохранены, но введен новый столбец и присвоены значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...