SQLite 插入约束字段时出错 - 为啥?
Posted
技术标签:
【中文标题】SQLite 插入约束字段时出错 - 为啥?【英文标题】:SQLite error inserting constraint field - why?SQLite 插入约束字段时出错 - 为什么? 【发布时间】:2020-04-09 14:31:52 【问题描述】:我是 android 编程和使用 SQLite 的新手。我正在尝试插入一个名为“menu”的数据库,该数据库有一个名为“items”的表。该表的属性是“名称”和“价格”,它们分别是文本和实数。 (我想为所有代码道歉,但我认为这些代码会有用)。我的“mysqliteHelper”类这样创建表:
package com.example.sqlite;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class MySQLiteHelper extends SQLiteOpenHelper
//Creating the items table
public static final String TABLE_ITEMS = "items";
public static final String ITEMS_COLUMN_NAME = "name";
public static final String ITEMS_PRICE = "price";
private static final String DATABASE_NAME = "menu";
private static final int DATABASE_VERSION = 1;
// create table comments(
// _id integer primary key autoincrement,
// comment text not null );
private static final String TABLE_CREATE_ITEMS = "create table "
+ TABLE_ITEMS + "( " + ITEMS_COLUMN_NAME + " text primary key, "
+ ITEMS_PRICE + " real not null );";
public MySQLiteHelper( Context context )
super( context, DATABASE_NAME, null, DATABASE_VERSION );
@Override
public void onCreate( SQLiteDatabase database )
//Create the items table
database.execSQL( TABLE_CREATE_ITEMS );
//Create the combos table
//database.execSQL(TABLE_CREATE_COMBO);
@Override
public void onUpgrade( SQLiteDatabase db, int oldVersion, int newVersion )
Log.w( MySQLiteHelper.class.getName( ), "Upgrading database from version "
+ oldVersion + " to " + newVersion + ", which will destroy all old data" );
db.execSQL( "DROP TABLE IF EXISTS" + TABLE_CREATE_ITEMS );
//db.execSQL( "DROP TABLE IF EXISTS" + TABLE_CREATE_COMBO );
onCreate( db );
我可以确认数据库“菜单”是在 data/data/package/databases 文件夹中创建的。虽然我无法使用 adb shell 连接到 SQLite,所以我无法确认表模式。单击插入按钮后,我的 datasource.createComment(String, Float) 被调用:
public void onClick (View v)
@SuppressWarnings("unchecked")
//Load up the current values in the adapter into this adapter object
ArrayAdapter<Comment> adapter = (ArrayAdapter<Comment>)getListAdapter();
//Set comment to null
Comment comment = null;
//Check to see which button was pressed
switch (v.getId())
case R.id.insert:
String[] option = new String[] "One", "Two", "Three";
int index = new Random().nextInt(3);
//When inserting comment you just have to pass value
comment = datasource.createComment("TEST", (float) 12.30);
adapter.add(comment); //Adding to listview
break;
case R.id.delete:
if(getListAdapter().getCount() > 0)
comment = (Comment)getListAdapter().getItem(0);
adapter.remove(comment);//removing from listview
datasource.deleteComment(comment); //delete from db.
break;
//Updating the adapter
adapter.notifyDataSetChanged();
通过一些调试(打印语句),我可以确认 database.insert 返回 -1。插入不成功。在我的 Logcat 中打印出以下错误
12-16 23:42:30.002 11063-11063/com.example.sqlite E/SQLiteDatabase: Error inserting price=12.3 name=TEST
android.database.sqlite.SQLiteConstraintException: error code 19: constraint failed
at android.database.sqlite.SQLiteStatement.native_executeInsert(Native Method)
at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:113)
at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1718)
at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1591)
at com.example.sqlite.CommentsDataSource.createComment(CommentsDataSource.java:47)
at com.example.sqlite.InsertItems.onClick(InsertItems.java:50)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at android.view.View$1.onClick(View.java:3039)
at android.view.View.performClick(View.java:3511)
at android.view.View$PerformClick.run(View.java:14105)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
我的“CommentsDataSource”的代码如下。请忽略 createComment() 之后的方法。我正在一次编辑我的教授代码一种方法。
public class CommentsDataSource
// Database fields
//Used toe xecute commands on db.
private SQLiteDatabase database;
//Opening up the mysqlhelper which is in charge of opening up connection and maintaining
private MySQLiteHelper dbHelper;
//Holds all the values from the database
private String[] allColumnsItems = MySQLiteHelper.ITEMS_COLUMN_NAME,
MySQLiteHelper.ITEMS_PRICE ;
//Creating the default constructor
public CommentsDataSource(Context context)
//Give context to the class that manages the connection
dbHelper = new MySQLiteHelper(context);
//Opening up the connction to the db
public void open() throws SQLException
//Open the db for reading and writing
database = dbHelper.getWritableDatabase(); //getWritableDatabase is what opens the connection
//Closing the database
public void close() throws SQLException
dbHelper.close();
//Creating and commiting comment
public Comment createComment(String comment, float price)
//Insert into comments values('')
ContentValues values = new ContentValues();
//Load the column id and value into ContentValues
values.put(MySQLiteHelper.ITEMS_COLUMN_NAME, comment);
values.put("price", price);
//Now insert into table
long insertID = database.insert(MySQLiteHelper.TABLE_ITEMS, null, values);
if(insertID == -1)
System.out.println("JSDLFJLSJDFL");
//Create a cursor to keep track of results. When creating cursors they equal database.query
Cursor cursor = database.query(MySQLiteHelper.TABLE_ITEMS, allColumnsItems, null, null, null, null, null);
//Move cursor tot he front
cursor.moveToFirst();
//Return the comment which is added to listview
return cursorToComment(cursor);
public void deleteComment(Comment comment)
// select id, comment from comments;
long id = comment.getId();
//Debug purposes
System.out.println("Comment to be deleted: " + id);
//Deleting from db
database.delete(MySQLiteHelper.TABLE_ITEMS, MySQLiteHelper.ITEMS_COLUMN_NAME + "=" + comment, null);
public List<Comment> getAllComments()
//Select * from comments
List<Comment> comments = new ArrayList<Comment>();
//Fetching the results of query into cursor
Cursor cursor = database.query(MySQLiteHelper.TABLE_ITEMS, allColumnsItems, null, null, null, null, null);
//Move to front of cursor
cursor.moveToFirst();
//Iterate through cursor
while(!cursor.isAfterLast())
Comment comment = cursorToComment(cursor);
//Add results to arraylist
comments.add(comment);
cursor.moveToNext();
cursor.close();
return comments;
public Comment cursorToComment(Cursor cursor)
Comment comment = new Comment();
comment.setId(cursor.getLong(0));
comment.setComment(cursor.getString(1));
return comment;
我正在努力找出我的错误在哪里。我的约束应该都是有效的?
【问题讨论】:
【参考方案1】:查看您的代码后,我可以假设您正在尝试在表格中使用唯一的项目名称,对吧?如果是这样,那么这个错误是显而易见的。在您的表items
中,您将name
作为主键,并且您每次都尝试插入TEST
。表中已经存在。
有 3 种方法可以解决这个问题。
-
从
name
列中删除主键约束。但是,您可以在此之后输入重复的名称。
不要在测试时对值进行硬编码。生成唯一名称并插入它。如下所示
int index = new Random().nextInt(3);
comment = datasource.createComment("TEST" + index, (float) 12.30);
// concatenate `index` variable to `TEST` that's it.
从用户 (GUI) 获取输入并将其插入到表格中。
PS:nextInt(3)
方法将返回从 0 到 2 的数字。当您测试代码时,您会得到重复的名称。因此,在使用随机数生成器时要小心。我想推荐我的最后一点。
【讨论】:
添加索引似乎已修复它。我完全忽略了这个事实。谢谢!如此简单的修复。 正如其他答案中所建议的,请将带有主键的_id
列添加到您的表中并自动递增。执行DELETE
、UPDATE
、SELECT
等操作会很有帮助。祝您编码愉快!
谢谢!我打算将评论或“测试”部分作为用户的输入。【参考方案2】:
在这里,您尝试使用文本主键创建表,理想情况下应该是自动增量。这就是它的返回约束失败的原因。
private static final String TABLE_CREATE_ITEMS = "create table "
+ TABLE_ITEMS + "( " + ITEMS_COLUMN_NAME + " text primary key, "
+ ITEMS_PRICE + " real not null );";
应该是
CREATE TABLE TableName(
_id INTEGER PRIMARY KEY, -- autoincrementing, for Android
NAME TEXT,
[...]);
你可以参考 Inserting values to SQLite table in Android
【讨论】:
啊,是的,我确实忘记了_id,但我仍然遇到同样的错误。【参考方案3】:请试试这个:
public void onClick (View v)
@SuppressWarnings("unchecked")
//Load up the current values in the adapter into this adapter object
ArrayAdapter<Comment> adapter = (ArrayAdapter<Comment>)getListAdapter();
//Set comment to null
Comment comment = new Comment(); //have to change this from null to new Comment();
//Check to see which button was pressed
switch (v.getId())
case R.id.insert:
String[] option = new String[] "One", "Two", "Three";
int index = new Random().nextInt(3);
//When inserting comment you just have to pass value
comment = datasource.createComment("TEST", (float) 12.30);
adapter.add(comment); //Adding to listview
break;
case R.id.delete:
if(getListAdapter().getCount() > 0)
comment = (Comment)getListAdapter().getItem(0);
adapter.remove(comment);//removing from listview
datasource.deleteComment(comment); //delete from db.
break;
//Updating the adapter
adapter.notifyDataSetChanged();
还有你的SQLiteOpenHelper
public class MySQLiteHelper extends SQLiteOpenHelper
//Creating the items table
public static final String TABLE_ITEMS = "items";
public static final String ITEMS_COLUMN_NAME = "name";
public static final String ITEMS_PRICE = "price";
private static final String DATABASE_NAME = "menu";
private static final int DATABASE_VERSION = 1;
// create table comments(
// _id integer primary key autoincrement,
// comment text not null );
private static final String TABLE_CREATE_ITEMS = "CREATE TABLE IF NOT EXISTS " + TABLE_ITEMS + "("
+ ITEMS_AUTO_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," //this is just _id
+ ITEMS_COLUMN_NAME + " VARCHAR,"
+ ITEMS_PRICE + " FLOAT)";
public MySQLiteHelper( Context context )
super( context, DATABASE_NAME, null, DATABASE_VERSION );
@Override
public void onCreate( SQLiteDatabase database )
//Create the items table
database.execSQL( TABLE_CREATE_ITEMS );
//Create the combos table
//database.execSQL(TABLE_CREATE_COMBO);
@Override
public void onUpgrade( SQLiteDatabase db, int oldVersion, int newVersion )
Log.w( MySQLiteHelper.class.getName( ), "Upgrading database from version "
+ oldVersion + " to " + newVersion + ", which will destroy all old data" );
db.execSQL( "DROP TABLE IF EXISTS" + TABLE_CREATE_ITEMS );
//db.execSQL( "DROP TABLE IF EXISTS" + TABLE_CREATE_COMBO );
onCreate( db );
【讨论】:
我已经在我的 createComment 方法中使用 ContentViews。基本上我所做的就是打包这些值,然后运行 SQliteDatabase 命令,对吧? 请试试这个。根据阅读***.com/questions/8117685/… .. 有一个空 另外,请删除您的onUpgrade()
代码。如果您更改数据库版本,它将删除数据库(即使您的表上有数据)
不幸的是,我遇到了同样的错误。我也不完全确定如何在 android studio 上正确调试。
尝试检查logcat并点击蓝色链接以上是关于SQLite 插入约束字段时出错 - 为啥?的主要内容,如果未能解决你的问题,请参考以下文章