Android - SQLite нет такого столбца, переданные столбцы игнорируются

ОТВЕТ. Для строковых полей необходимо заключать их в одинарные кавычки.

Я продолжаю получать сообщение «нет такого столбца: значение (код 1)», не понимая, почему.

Я пытаюсь хранить людей с индексами, чтобы я мог их однозначно идентифицировать и извлекать более сложные данные, которые не нужно запрашивать как json, для чего я использую Gson для преобразования в Json и из объекта.

Отредактирован запрос на создание, чтобы показать работающую функцию UNIQUE. Здесь вы можете найти дополнительную информацию о ключевых словах ON CONFLICT

//Creation query
private static final String CREATE_PERSON_TABLE = "CREATE TABLE IF NOT EXISTS
    "+PERSON_TABLE_NAME+" (id INTEGER PRIMARY KEY, firstname VARCHAR, lastname VARCHAR,
    zipcode VARCHAR, birthdate VARCHAR, json VARCHAR,
    UNIQUE(lastname, zipcode, birthdate) ON CONFLICT REPLACE);";

//Insert or replace query execution
getWritableDatabase().execSQL("INSERT OR REPLACE INTO "+PERSON_TABLE_NAME+"
(firstname, lastname, zipcode, birthdate, json) VALUES 
("+person.getFirstname()+","+person.getLastName()+","+person.getZipcode()+",
'"+person.getBirthdate+"','"+person.getLifestoryJson()+"')");

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

android.database.sqlite.SQLiteException: no such column: Hank (code 1): , while compiling: INSERT OR REPLACE INTO person (firstname, 
lastname, zipcode, birthdate, json) VALUES (Hank,Hairy,8888HH,'06-01-1966','{"events":"[]","comments":[],"storyList":[],"favoriteFoods":"cheddar","peperoni":"lasagna"}')
            at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
            at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:882)
            at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:493)
            at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
            at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
            at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
            at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1663)
            at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1594)

Я часами смотрю и сравниваю с учебниками, я просто не вижу, что происходит не так. Похоже, что по какой-то причине столбцы, которые я передаю, игнорируются, а вместо этого используются значения в качестве столбцов. Любая помощь или объяснение того, что может вызвать эту ошибку, очень ценятся.


person G_V    schedule 06.01.2015    source источник


Ответы (2)


Строки необходимо заключать в кавычки:

getWritableDatabase().execSQL("INSERT OR REPLACE INTO "+PERSON_TABLE_NAME+"
(firstname, lastname, zipcode, birthdate, json) VALUES 
('"+person.getFirstname()+"','"+person.getLastName()+"','"+person.getZipcode()+",
'"+person.getBirthdate+"','"+person.getLifestoryJson()+"')");

Каким-то образом вы обернули дату, историю жизни, но не имя, фамилию и почтовый индекс.

person Simas    schedule 06.01.2015
comment
Еще лучше, если вы привяжете параметры с помощью заполнителя ?. - person Phantômaxx; 06.01.2015
comment
@DerGolem правда, это было бы более читабельно. Однако мне не хотелось переписывать все это для ОП :) - person Simas; 06.01.2015
comment
Ах, да, я завернул их, потому что в них много пробелов, я попробую сейчас и вернусь к вам как можно скорее! - person G_V; 06.01.2015
comment
Кроме того, поскольку вы уже вызываете getWritableDatabase(), может быть проще использовать методы insert() или insertOrThrow() или insertWithOnConflict(). - person clockwerk; 06.01.2015
comment
Похоже, что главная проблема действительно заключалась в одинарных кавычках, я не знал, что они мне нужны везде! @Der Golem Чтобы сделать его чище, я должен поместить запрос в отдельную строку и использовать `table_name (field1=?, field2=?) или как это вообще будет работать. Если бы вы могли указать мне на учебник, это было бы здорово, так как я имитировал те, которые я нашел до сих пор. @ crn14 crn14 Я посмотрел на вставку и замену, вставкаWithOnConflict ведет себя как ВСТАВКА ИЛИ ЗАМЕНА? У меня есть в общей сложности 5 часов опыта работы с SQLite, так что не бойтесь говорить со мной, как будто я не понимаю, скорее всего, я этого не понимаю. - person G_V; 06.01.2015
comment
@G_V быстрый поиск Google вернул это. Не лучший, но код выглядит нормально. Просто найдите на странице insert(. - person Simas; 06.01.2015
comment
@G_V: вам не нужны одинарные кавычки on everything. Только для строковых полей. Чтобы передать связанные параметры, вы должны передать массив строк со значениями (см. перегрузки методов rawQuery() и execSQL()). - person Phantômaxx; 06.01.2015
comment
@DerGolem Документы для Android предлагают не использовать execSQL для вставки. - person Simas; 06.01.2015
comment
@user3249477 Абсолютно неверно. Это не говорит ничего подобного. - person Phantômaxx; 06.01.2015
comment
@DerGolem Должно быть, я пьян, но проверь ссылку в моем предыдущем комментарии. - person Simas; 06.01.2015
comment
@user3249477 user3249477 Да, я так думаю. Он говорит: It has no means to return any data (such as the number of affected rows). Instead, you're encouraged to use insert Что буквально означает, что execSQL() не возвращает количество затронутых строк, поэтому вам рекомендуется использовать метод insert() (который я действительно поссать). - person Phantômaxx; 06.01.2015
comment
@DerGolem, лол. Мочите сколько хотите, я все еще думаю, что методы вставки - это то, что вам нужно. execSQL не обеспечивает никакой проверки ошибок. Но эй, это мое мнение :) - person Simas; 06.01.2015
comment
@user3249477 user3249477 Для такого опытного разработчика, как я, просмотр полной строки SQL означает контроль. Я проверяю свои команды в отдельном инструменте, на отдельной копии БД. И я использую транзакции для решения проблем (все обновления базы данных зафиксированы или все обновления базы данных отклонены). Это действительно правильный путь. - person Phantômaxx; 06.01.2015
comment
Прямо сейчас я изучаю использование более чистого кода со вставкой значений, передавая как запрос, так и значения по отдельности. Я понятия не имею, что я делаю, но все это увлекательно. - person G_V; 06.01.2015
comment
@G_V I have no idea what I'm doing Это и fascinating, и confusing. И даже potentially dangerous. - person Phantômaxx; 06.01.2015
comment
Вы говорите мне, что SQLite уязвим для инъекций, делая это красиво? - person G_V; 06.01.2015

Я не знаю, имеет ли это какое-либо отношение к вашей проблеме, но я считаю, что для SQLite разрешены следующие типы данных:

INTEGER, TEXT, BLOB, REAL и NUMERIC

так что ваш оператор создания таблицы может вызывать некоторые проблемы.

вот другой оператор создания таблицы:

CREATE TABLE 'person_table_name' (
    'id'            INTEGER,
    'first_name'    TEXT,
    'last_name'     TEXT,
    'zipcode'       TEXT,
    'birthdate'     TEXT,
    'json'          TEXT,
    PRIMARY KEY(id)
);

ваш уникальный индекс может измениться на:

CREATE UNIQUE INDEX 
person_unique 
ON 
person_table_name (first_name, last_name, zipcode, birthdate);

ваша вставка или замена в операторе может измениться на:

INSERT OR REPLACE INTO 
person_table_name (first_name, last_name, zipcode, birthdate, json) 
VALUES (
    'Hank', 
    'Hairy',
    '8888HH',
    '06-01-1966',
    '{"events":"[]","comments":[],"storyList":[],"favoriteFoods":"cheddar","peperoni":"lasagna"}'
);

Я использовал «Браузер БД для SQLite» (небольшая программа для создания БД и тестовых операторов sqlite и т. д.)

все приведенные выше операторы выполнены успешно.

Я думаю, что для вашей конкретной ситуации вам нужно изменить следующее для вашего конкретного утверждения:

getWritableDatabase().execSQL("INSERT OR REPLACE INTO " +
PERSON_TABLE_NAME + "(firstname, lastname, zipcode, birthdate, json) +
VALUES ('" + person.getFirstname() + "','" + person.getLastName() + "','" + person.getZipcode() + "','" + person.getBirthdate + "','" + person.getLifestoryJson() + "')");

похоже, что у вас нет ' (одинарная кавычка) вокруг вызовов методов person.getFirstName() и person.getLAstName()

person clockwerk    schedule 06.01.2015
comment
Спасибо за ваш очень хорошо написанный ответ, я использовал sqlite.org/datatype3.html, и это действительно были одинарные кавычки. - person G_V; 06.01.2015