I'm extending the SQLiteOpenHelper class to help me connect and do my database work. According to the documentation, the OnCreate method should only be called if the database has not been created. Yet, my problem is that I am getting this error when I try to execute a query to insert a record.
ERROR/Database(214): Failure 1 (table Sample already exists) on 0x218688 when preparing
'CREATE TABLE Sample (RecId INT, SampleDesc TEXT);'.
The only place this Create query is used in code is the OnCreate method which looks like this.
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SAMPLE_TABLE_CREATE);
}
Note: I'm following a tutorial - the only thing I've done different is make the SQLiteDatabase object public instead of private so that I could extend this class for each entity, letting the public SQLiteDatabase object from the inherited DataHelper class do all the work
Here is the method that makes the call that fails.
//This method is in the class that extends DataHelper (See note on tutorial)
public void createSample(Sample sample)//next action form
{
String id = sample.getId();
String name = sample.getSummary();
String query = "INSERT INTO " + SAMPLE_TABLE_NAME + "( " + SAMPLE_Id + "," +
SAMPLE_NAME + ") " + " VALUES (" + id + "," + name + ")";
try{
data.rawQuery(query, null);
}
catch(SQLException e){
Log.i("Sample", "Errors: Sample LN60: " + e.getMessage());
}
}
Can someone tell me what I'm doing wrong? Or maybe a hack (i.e. check if table exists before executing create statement)
Please let me know what other code I can post to solve this...
Is it due to you've execute it your activity once and never destroy the DB after that?
And 2nd run you'd hit this error.
Database is stored in /data/data/YOUR_PACKAGE/databases/, so a workaround would be to check if the DB exists here before creating it.
//The Android's default system path of your application database.
private static String DB_PATH = "/data/data/YOUR_PACKAGE/databases/";
private static String DB_NAME = "myDBName";
SQLiteDatabase checkDB = null;
String myPath = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
if(checkDB){
//do nothing
}else{
//create DB
}
Code source here
The first error is quite simply because you are creating a table that already exists, so yes adding a check if the table exists prior to creating it would be good. Once an SQLite dB is created or made it will stay until someone or something deletes it, unlike the default onCreate() call which resembles re-creating or drawing your screen.
every time you call getWritableDatabase() onCreate() method is called.
Related
In my application I have a content provider which uses a database for the content provided. When the database is created the first time it needs to be filled from the raw content of a Json file. My idea was that i trigger this filling of the database at onCreate of my SQLiteOpenHelper subclass. This works fine yet I am not sure how to handle the the communication between application and content provider when the app is running the first time. Basically i would like to show some sort of a splash screen while the database is filled. Yet how does the application get informed that
the content provider is busy filling the database when running the first time
the content provider is ready to go
Surely I could fill the database from the application by calling the content provider with each dataset yet I would prefer doing it within the sphere of the content provider so that the application does not have to handle the reading of the json file etc. Besides design preferences it would also enable the content provider to fill the database more efficiently because it would have the whole dataset at once. I have a feeling this is not possible yet I hope I miss some simple point.
Any suggestions how to achieve this would be highly appreciated.
Thanks
martin
When using a content Provider i would presume that your using a DBHelper class to manage the creation of the database. Below is the code from the android notes example project.
This shows how the DBHelper constructor is intelligent enough to determine if the database has been created before. In the createDatabase method i would subsequently call a method to pre-populate the database, from as you say a json file.
The problem is that this doesn't really allow you to communicate to the Activity that your database hasn't been initialised.
One thought could be that you use SharedPreferences to store the fact you've populated the database. You could then check the sharedPreference in the activity on startup, Call the content provider to populate the database and then store in the shared preference that you've done this task already.
Just be aware that i'm not sure if the sharedPreferences maintain the same state as the database if you for example erase the data from the android settings menu. You'd need to check that.
http://code.google.com/p/android-notes/source/browse/trunk/src/com/bitsetters/android/notes/DBHelper.java?r=10
public class DBHelper {
private static final String DATABASE_NAME = "notes";
private static final String TABLE_DBVERSION = "dbversion";
private static final String TABLE_NOTES = "notes";
private static final int DATABASE_VERSION = 1;
private static String TAG = "DBHelper";
Context myCtx;
private static final String DBVERSION_CREATE =
"create table " + TABLE_DBVERSION + " ("
+ "version integer not null);";
private static final String NOTES_CREATE =
"create table " + TABLE_NOTES + " ("
+ "id integer primary key autoincrement, "
+ "note text, "
+ "lastedit text);";
private static final String NOTES_DROP =
"drop table " + TABLE_NOTES + ";";
private SQLiteDatabase db;
/**
*
* #param ctx
*/
public DBHelper(Context ctx) {
myCtx = ctx;
try {
db = myCtx.openOrCreateDatabase(DATABASE_NAME, 0,null);
// Check for the existence of the DBVERSION table
// If it doesn't exist than create the overall data,
// otherwise double check the version
Cursor c =
db.query("sqlite_master", new String[] { "name" },
"type='table' and name='"+TABLE_DBVERSION+"'", null, null, null, null);
int numRows = c.getCount();
if (numRows < 1) {
CreateDatabase(db);
} else {
int version=0;
Cursor vc = db.query(true, TABLE_DBVERSION, new String[] {"version"},
null, null, null, null, null,null);
if(vc.getCount() > 0) {
vc.moveToFirst();
version=vc.getInt(0);
}
vc.close();
if (version!=DATABASE_VERSION) {
Log.e(TAG,"database version mismatch");
}
}
c.close();
} catch (SQLException e) {
Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage());
} finally {
db.close();
}
}
private void CreateDatabase(SQLiteDatabase db)
{
try {
db.execSQL(DBVERSION_CREATE);
ContentValues args = new ContentValues();
args.put("version", DATABASE_VERSION);
db.insert(TABLE_DBVERSION, null, args);
db.execSQL(NOTES_CREATE);
// Populate with data
populateDataBaseFromFile();// There are probably better ways to do this.
setSharedPreferenceYouPopulatedDB();
} catch (SQLException e) {
Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage());
}
}
Personally I wouldn't bother with the splash screen, unless you really needed to.
Another thought might be to:
Write in the db helper a method to determin if your tables exist. Return false if not.
In startup activity call ContentProvider with a request that calls the DBHelper test method.
If false then display splash screen and then call Content Provider to populate DB.
If true, then carry on as normal.
My app's got a database with three tables in it: one to store the names of the people it tracks, one to track an ongoing event, and one - for lack of a better term - for settings.
I load the first table when the app starts. I ask for a readable database to load in members to display, and later I write to the database when the list changes. I've had no problems here.
The other two tables, however, I can't get to work. The code in the helper classes is identical with the exception of class names and column names, and (at least until the point where I try to access the table) the code to use the table is nearly identical as well.
Here's the code for my helper class (I've got a separate helper for each table, and as I said, it's identical except for class names and columns):
public class db_MembersOpenHelper extends SQLiteOpenHelper
{
public static final String TABLE_NAME = "members_table";
public static final String[] COLUMN_NAMES = new String[] {
Constants.KEY_ID,
"name",
"score"
};
private static final String TABLE_CREATE = "CREATE TABLE " + TABLE_NAME + " ("
+ COLUMN_NAMES[0] + " INTEGER PRIMARY KEY autoincrement, "
+ COLUMN_NAMES[1] + " TEXT, "
+ COLUMN_NAMES[2] + " INTEGER);";
public db_MembersOpenHelper(Context context)
{
super(context, Constants.DATABASE_NAME, null, Constants.DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) { db.execSQL(TABLE_CREATE); }
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
Log.w("TaskDBAdapter", "Upgrading from version " + oldVersion + " to " + newVersion + ".");
// Do nothing. We do not have any updated DB version
}
}
Here's how I use it successfully:
db_MembersOpenHelper membersDbHelper = new db_MembersOpenHelper(this);
SQLiteDatabase membersDb = membersDbHelper.getReadableDatabase();
Cursor membersResult = membersDb.query(TABLE_NAME, null, null, null, null, null, null);
members = new HashMap<String, Integer>();
membersResult.moveToFirst();
for(int r = 0; r < membersResult.getCount(); r++)
{
members.put(membersResult.getString(1), membersResult.getInt(2));
membersResult.moveToNext();
}
membersDb.close();
And here's where it fails:
db_PlayersOpenHelper playersDbHelper = new db_PlayersOpenHelper(this);
final SQLiteDatabase playersDb = playersDbHelper.getWritableDatabase();
if(newGame)
{
for(String name : players)
{
ContentValues row = new ContentValues();
row.put(COLUMN_NAMES[1], name);
row.put(COLUMN_NAMES[2], (Integer)null);
playersDb.insert(TABLE_NAME, null, row);
}
}
The first one works like a charm. The second results in ERROR/Database(6739): Error inserting achievement_id=null name=c
android.database.sqlite.SQLiteException: no such table: players_table: , while compiling: INSERT INTO players_table(achievement_id, name) VALUES(?, ?);
...
I did do some testing, and the onCreate method is not being called at all for the tables that aren't working. Which would explain why my phone thinks the table doesn't exist, but I don't know why the method isn't getting called.
I can't figure this out; what am I doing so wrong with the one table that I accidentally did right with the other?
I think the problem is that you are managing three tables with with three helpers, but only using one database. SQLiteOpenHelper manages on database, not one table. For example, it checks to see whether the database, not table, exists when it starts. It already does, so onCreate() does not fire.
I would manage all tables with one helper.
Let me see if I get this right. You are trying to create one database with three tables. But when you create the database, you create just one table; you are somehow instantiating the same database at a different place and wonder why its onCreate method doesn't get called. Is this a correct interpretation?
My strategy would be to try and create all three tables in the single onCreate() method.
If you are working with multiple tables, then you have to create all of the tables at once. If you have run your application first and later you update your database, then it will not upgrade your DB.
Now delete your application, then run it again.
There is one more solution but it is not proper. You can declare onOpen method in which you can call onCreate. And add IF NOT EXISTS before table name in your create table string. – Sourabh just now edit
I am creating a database and I'm inserting a row like so:
/* Add two DataSets to the Table. */
myDB.execSQL("INSERT INTO "
+ MY_DATABASE_TABLE
+ " (LastName, FirstName, Country, Age)"
+ " VALUES ('Gramlich', 'Nicolas', 'Germany', 20);");
myDB.execSQL("INSERT INTO "
+ MY_DATABASE_TABLE
+ " (LastName, FirstName, Country, Age)"
+ " VALUES ('Doe', 'John', 'US', 34);");
I have two questions regarding the above code:
How do I disallow duplicate records? I want to check incoming data at the insert time. How can I achieve that? Should I use IF NOT EXISTS?
How can I check whether that database is available or not? So far, without any success, I've tried:
private static String DB_PATH = "/data/data/YOUR_PACKAGE/databases/myDBName";
private static String DB_NAME = "myDBName";
private boolean checkDataBase() {
SQLiteDatabase checkDB = null;
try {
checkDB = SQLiteDatabase.openDatabase(DB_PATH, null,
SQLiteDatabase.OPEN_READONLY);
checkDB.close();
} catch (SQLiteException e) {
// database doesn't exist yet.
}
return checkDB != null ? true : false;
}
Any suggestions on how to achieve this?
to prevent duplicates create a UNIQUE INDEX on that table.
At runtime, you have at least two options:
let the index give you an exception if you attempt a duplicate, then catch that exception and do something else, or
Query the table pro-actively to see if the new record exists, and if you find it you know there is a duplicate, so do something else.
Here are a few suggestions:
When creating your tables, define the columns that you want to prevent duplicates as UNIQUE.
Your checkDataBase() method is a bit strange. Have you considered using the SQLiteOpenHelper class in your implementation to simplify things?
http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html
I have built a database helper class with an open() method and extended sqlite helper with onCreate() overridden. (shown below). Despite all of this, I am getting 'SQLiteException, no such table' error. I do not understand, why is the openHelper not helping?
public void open() {
try{
db = openHelper.getWritableDatabase();
} catch (SQLiteException e) {
db = openHelper.getReadableDatabase();
}
}
//other stuff
public static final String database_create = "create table " + database_table + " (" + primary_key + " integer primary key autoincrement, "
+ company_column + " text not null, " + product_column + " text not null);";
#Override
public void onCreate(SQLiteDatabase _db) {
_db.execSQL(database_create);
}
the following code is meant to insert an entry temporarily, because the database cannot be empty for other reasons. It seems to execute perfectly, yet the last bit of code, which comes after is what throws the error
CompanyAndProductDatabaseAdapter cpdAdapter = new CompanyAndProductDatabaseAdapter(this);
cpdAdapter.open();
errorguard = cpdAdapter.insertPair("Loading", "...");
cpdAdapter.close();
//other stuff
cpdAdapter.open();
Cursor cursor = cpdAdapter.getAllPairsCursor(); //error here
cursor.requery();
startManagingCursor(cursor);
I don't know why you implemented a open-method, also the database_create is not what it should be.
I assume the first code is part of CompanyAndProductDatabaseAdapter.
Take a look here:
Android - Sqlite database method undefined fot type
That's almost all you need to create/get a DB with inherted SQLiteOpenHelper.
Your problem is this function:
db = openHelper.getWritableDatabase();
db = openHelper.getReadableDatabase();
First: check your path/name of the database is correct. It can create a default database, an empty database ( no tables, no nothing) if the database is not found.
Second: try to open your database this way:
String myPath = DB_PATH + DB_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE); // or OPEN_READONLY, depending on situation.
I am creating my SQLite database for my App at runtime if it does not exist and insert rows if it does. Since it is supposed to be created at runtime and I have implemented it by creating a subclass of SQLiteOpenHelper and overriding the onCreate() method -
"Do I need to put anything in the /assets folder of my project?"
I am not using any Content Provider "Do I need to add any tags in the AndroidManifest.xml?"
Here is what I have done. The strings have been defined properly and I do not get any runtime exceptions.
Implementation of the SQLiteOpenHelper subclass.
public class MyDB extends SQLiteOpenHelper {
public MyDB(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION );
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(USERAUTH_TABLE_CREATE);
db.execSQL(USERPREF_TABLE_CREATE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int
newVersion) {
Log.w("Example", "Upgrading database, this will drop tables and
recreate.");
db.execSQL("DROP TABLE IF EXISTS " + USERAUTH_TABLE_NAME);
db.execSQL("DROP TABLE IF EXISTS " + USERPREF_TABLE_NAME);
onCreate(db);
}
}
Here is where I create an instance of the MyDB subclass of the SQLiteOpenHelper.
MyDB tdb = new MyDB(Activity.this);
SQLiteDatabase db = tdb.getReadableDatabase();
Everything runs and when I go to the sqlite shell and write the following query
select * from table_name - it just tells me no such record exist. I set breakpoints and it seems after the getReadableDatabase() is called the #Override OnCreate() method is never executed which is where I execute the Create table SQLs. I have tried getWritableDatabase()
as well.
I dont understand why the tables are not being created. If anyone can help that would be awesome.
Thanks.
Query Text String#1
private static final String USERAUTH_TABLE_CREATE =
"CREATE TABLE " + USERAUTH_TABLE_NAME + " (" +
"number INTEGER NOT NULL," +
"dip TEXT NOT NULL," +
"email TEXT NOT NULL," +
"password TEXT NOT NULL," +
"flag INTEGER" + ");" ;
Query Text String #2
private static final String USERPREF_TABLE_CREATE =
"CREATE TABLE " + USERPREF_TABLE_NAME + " (" +
"tpd TEXT NOT NULL ," +
"cat TEXT NOT NULL" + ");";
If onCreate() is not being called, then the database has already been created for your app. The quickest way to solve it is to delete your project on the emulator (Settings --> Applications --> Your application), and then restart your application. Alternatively you could use ADB to just drop your database -- it's up to you. Restarting the app after dropping the database will call onCreate() because the database does not exist, and then your table creation sql will be run. onCreate() is only called if your database DOES NOT exist (so pretty much the first time you call the database in your code.
"Do I need to put anything in the /assets folder of my project?"
No
"Do I need to add any tags in the AndroidManifest.xml?"
No
Your syntax is ok ... could you paste the query you are making for creating tables ?
This might be a silly question, but have you defined the DATABASE_NAME and DATABASE_VERSION variables?
Issue resolved. Code was working all the way once again. sqlite shell was not showing me the tables and the database. When I kept my app running on the emulator and navigated to data > data > your-package-name > databases > your-database-file using DDMS the system shows me the SQLite DB was created fine. I have checked the tables are there as well.
Thank you all guys!!
This simple application will create a data base and 1 table w and at the end it will
retrieve the value which u have enetered and vl show in textBox.
SQLiteDatabase myDB= null;
String TableName="Profile";
String ShowData="";
/* This function create new database if not exists. */
try {
myDB = openOrCreateDatabase("DataBase.db",SQLiteDatabase.CREATE_IF_NECESSARY, null);
/* Create a Table in the Database. */
myDB.execSQL("CREATE TABLE IF NOT EXISTS "+ TableName + " (id INT(4),firstname VARCHAR,lastname VARCHAR);");
/* Insert data to a Table*/
//myDB.execSQL("INSERT INTO "+ TableName +"(id, firstname, lastname) "+ " VALUES (1, 'Pir', 'Fahim');");
Toast.makeText(this," DATA BASE HAVE BEEN CREATED ", Toast.LENGTH_SHORT).show();
/*Fetch data from database table */
Cursor c = myDB.rawQuery("SELECT* FROM " + TableName , null);
int id = c.getColumnIndex("id");
int fristName = c.getColumnIndex("firstname");
int lastName = c.getColumnIndex("lastname");
// Check result.
c.moveToFirst();
if (c != null) {
// Loop through all Results
do {
int personId = c.getInt(id);
String FirstName = c.getString(fristName);
String LastName = c.getString(lastName);
ShowData =ShowData +personId+" .) " +FirstName+" "+LastName+"\n";
txt.append("********************"+"\n"+personId+"\n"+FirstName+"\n"+LastName+"\n");
// Toast.makeText(this," RESULT 2 IS = "+ ShowData, Toast.LENGTH_LONG).show();
}
while(c.moveToNext());
}
// Toast.makeText(this," RESULT 2 IS = "+ ShowData, Toast.LENGTH_LONG).show();
}
catch(Exception e)
{
Toast.makeText(this, "Error = "+e.getMessage(), Toast.LENGTH_LONG).show();
}
finally
{
if (myDB != null)
myDB.close();
}