creating two tables in android app database - android

I'm trying to create two tables in my android app database and the application crashes when i'm tring to insert values to the first table, but when i delete the database and recreate it only with one table, it works fine. i don't get it?
the code is:
private static String query_create_user = "CREATE TABLE User ( email TEXT PRIMARY KEY, firstName TEXT, lastName TEXT, password TEXT)";
private static String query_create_group = "CREATE TABLE Group ( groupNumber INTEGER PRIMARY KEY AUTOINCREMENT, courseNumber INTEGER, groupName TEXT, groupType TEXT, groupOwner TEXT)";
public SchoolBagDataBase (Context applicationcontext) {
super(applicationcontext, "contract.db", null, 1);
}
#Override
public void onCreate(SQLiteDatabase database) {
database.execSQL(query_create_user);
database.execSQL(query_create_group);
}
thanks in advance!

The SQL statement held in string 'query_create_group' is invalid. You can't have a table called Group because GROUP is a reserved word in SQLite. Just choose a different name for your table.

Related

connecting two tables with foreign keys in sqlite

Hi in my senario there is a table with 4 columns and im trying to create another table with connection to the first table but i dont whay im getting this error in logcat
2019-10-28 01:04:00.853 29812-29812/com.test.fastfoodfinder E/SQLiteDatabase: Error inserting notes_main=testeststststststststs
android.database.sqlite.SQLiteException: no such table: notes (code 1 SQLITE_ERROR): , while compiling: INSERT INTO notes(notes_main) VALUES (?)
so i have created a class for my data base and this is what i have done
public class RestaurantDBHelper extends SQLiteOpenHelper {
private final static String DATABASE_NAME = "FastFood_DataBase.db";
private final static int DATABASE_VERSION = 1;
private final static String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME +
"(" + COLUMN_RESTAURANT_ID + " INTEGER PRIMARY KEY ," +
COLUMN_RESTAURANT_NAME + " TEXT, " +
COLUMN_RESTAURANT_ADDRESS + " TEXT, " +
COLUMN_RESTAURANT_TYPE + " INTEGER, " +
COLUMN_RESTAURANT_IMAGE + " INTEGER);";
private final static String CREATE_TABLE_NOTES = "CREATE TABLE " + TABLE_NAME_NOTES +
"(" + COLUMN_NOTES_ID + " INTEGER PRIMARY KEY, "
+ COLUMN_NOTES + " TEXT," + "FOREIGN KEY (" + COLUMN_NOTES_ID + ") REFERENCES " + TABLE_NAME +"(restaurant_id) ON DELETE CASCADE)";
public final static String DELETE_TABLE = "DROP TABLE IF EXISTS " + TABLE_NAME;
public RestaurantDBHelper(#Nullable Context context){
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("PRAGMA FOREIGN_KEYS = ON;");
db.execSQL(CREATE_TABLE);
db.execSQL(CREATE_TABLE_NOTES);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(DELETE_TABLE);
onCreate(db);
}
public void addRestaurant(Restaurant restaurant) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_RESTAURANT_NAME, restaurant.getName());
values.put(COLUMN_RESTAURANT_ADDRESS, restaurant.getAddress());
values.put(COLUMN_RESTAURANT_TYPE,restaurant.getType());
values.put(COLUMN_RESTAURANT_IMAGE, restaurant.getType());
db.insert(TABLE_NAME, null, values);
db.close();
}
public void addNotes (Restaurant restaurant) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_NOTES,restaurant.getNote());
db.insert(TABLE_NAME_NOTES,null,values);
db.close();
}
and
public class RestaurantContract {
public static class EntryRestaurants {
public final static String TABLE_NAME = "restaurants";
public final static String COLUMN_RESTAURANT_ID = "restaurant_id";
public final static String COLUMN_RESTAURANT_NAME = "restaurant_name";
public final static String COLUMN_RESTAURANT_ADDRESS = "restaurant_address";
public final static String COLUMN_RESTAURANT_TYPE = "restaurant_type";
public final static String COLUMN_RESTAURANT_IMAGE = "restaurant_image_type";
public final static String COLUMN_RESTAURANT_NOTE_ID = "note_id";
public final static String TABLE_NAME_NOTES = "notes";
public final static String COLUMN_NOTES_ID = "notes_id";
public final static String COLUMN_NOTES = "notes_main";
public final static int RESTAURANT_TYPE_DELIVERY = 1;
public final static int RESTAURANT_TYPE_SITDOWN = 2;
public final static int RESTAURANT_TYPE_TAKEAWAY = 3;
}
}
im kind a new in android so any help would be appreciated,thanks
I believe that your issue is with the onCreate method. This ONLY runs when the database is created, it does not run every time the App is run.
The easiest solution, assuming that you do not need to keep any existing data, is to either delete the App's data or to uninstall the App. After doing either rerun the App and the new table will be created as the onCreate method will then run.
Furthermore it is no use turning FOREIGN KEYS on in the onCreate method. FOREIGN KEYS need to be turned on every time the App is run. To fix this, override the onConfigure method and then use db.setForeignKeyConstraintsEnabled(true);
this is just a convenient alternative to using db.execSQL("PRAGMA FOREIGN_KEYS = ON;");, so if you prefer you could use this when overriding the onConfigure method.
e.g. add this method to the RestaurantDBHelper class :-
#Override
public void onConfigure(SQLiteDatabase db) {
super.onConfigure(db);
db.setForeignKeyConstraintsEnabled(true);
}
However, you will then have issues when trying to add notes as the child will be set to null and thus their will not be a link/map/association/reference between the added note and the restaurant.
You need to use something like :-
public long addNote(String note, long restaurantId) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_NOTES,note);
values.put(COLUMN_NOTES_ID,restaurantId);
return db.insert(TABLE_NAME_NOTES,null,values);
}
BUT then you may then have an issue as to determining the id of the restaurant.
BUT then you may then encounter a further issue in that you could only have one note per restaurant as the column used to reference the restaurant is defined as INTEGER PRIMARY KEY and is therefore is a UNIQUE column (the same value can only be used once (an exception is null as a null is considered to be unique to another null)).
If the requirement is for one note per restaurant then there is no need for the separate table the relationship is a one to one relationship so the value can be stored in the restaurant table.
If you want a restaurant to have multiple notes (one to many relationship) then you should not make the column INTEGER PRIMARY KEY, INTEGER would suffice. Then a number of notes could reference the same restaurant.
If you wanted a note to be able to be be applied to a number of restaurants then you'd use a third mapping/line/reference/associative table (other name probably also exist). Such a table would have two columns one to reference the restaurant and the other to reference the note. You would then have a many to many relationship between restaurants and notes (a note could be used by many restaurants and a restaurant could use many notes).
You may find The 3 Types of Relationships in Database Design helpful.
You have enabled foreign key constraints and thus must have a unique primary key for the foreign key to reference.
https://sqlite.org/foreignkeys.html#fk_indexes
says
If the database schema contains foreign key errors that require looking at more than one table definition to identify, then those errors are not detected when the tables are created. Instead, such errors prevent the application from preparing SQL statements that modify the content of the child or parent tables in ways that use the foreign keys. Errors reported when content is changed are "DML errors" and errors reported when the schema is changed are "DDL errors". So, in other words, misconfigured foreign key constraints that require looking at both the child and parent are DML errors. The English language error message for foreign key DML errors is usually "foreign key mismatch" but can also be "no such table" if the parent table does not exist. Foreign key DML errors are reported if:
The parent table does not exist, or
The parent key columns named in the foreign key constraint do not exist, or
The parent key columns named in the foreign key constraint are not the primary key of the parent table and are not subject to a unique constraint using collating sequence specified in the CREATE TABLE, or
The child table references the primary key of the parent without specifying the primary key columns and the number of primary key columns in the parent do not match the number of child key columns.
Given that you never give the restaurant_id a value when you inserting a restaurant then the primary key of the restaurants is probably always null and thus not unique
(Yes according to https://www.sqlitetutorial.net/sqlite-primary-key/ to make the current version of SQLite compatible with the earlier version, SQLite allows the primary key column to contain NULL values. )
So I would say the solution is to create restaurant entries with a unique primary key value when you insert a restaurant or get the database to generate a unique value creating the the restaurant table with the line:-
private final static String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME +
"(" + COLUMN_RESTAURANT_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
....
One way to confirm this is download FastFood_DataBase.* files using Device Explorer in your app's database directory and then open it up in https://sqlitebrowser.org/ on your computer to confirm the contents.

Sqlite column fails to create in creation time

I'm facing a strange problem. I'm creating a db in sqlite with the below query
String GROUP_TABLE = "groups";
String ROW_ID = "rowid";
String GROUP_ID = "GroupID";
String GROUP_NAME = "GroupName";
String GROUP_STATUS = "GroupStatus";
String IS_ADMIN = "IsAdmin";
String GROUP_TYPE = "GroupType";
String IS_PUBLIC = "IsPublic";
String LAST_UPDATE = "LastUpdate";
String groupQuery = "CREATE TABLE IF NOT EXISTS "+ GROUP_TABLE +" ("
+ROW_ID+" INTEGER PRIMARY KEY, "
+GROUP_ID+" TEXT, "
+GROUP_NAME+" TEXT, "
+GROUP_STATUS+" TEXT, "
+GROUP_TYPE+" TEXT, "
+IS_ADMIN+" TEXT, "
+IS_PUBLIC+" TEXT, "
+LAST_UPDATE+" TEXT);";
This is the schema given by sqlite adb command
H:\adt-bundle-windows-x86_64-20140702\sdk\platform-tools>sqlite3
SQLite version 3.8.10.2 2015-05-20 18:17:19
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .open mydb.db
sqlite> .full schema
Usage: .fullschema
sqlite> .fullschema
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE groups (rowid INTEGER PRIMARY KEY, GroupID TEXT, GroupName TEXT, GroupStatus TEXT, GroupType TEXT, IsAdmin TEXT, IsPubli
c TEXT, LastUpdate TEXT);
/* No STAT tables available */
and when I enter records for the first time there will be no problem. But when I try to enter records next time i get
E/SQLiteLog﹕ (1) table groups has no column named LastUpdate
11-04 14:35:01.850 11947-11974/? E/SQLiteDatabase﹕ Error inserting GroupType=1 GroupID=553 LastUpdate=2015-08-08T14:17:14.000Z IsAdmin=1 GroupName=SAIFOOTWEARS GroupStatus=1
android.database.sqlite.SQLiteException: table groups has no column named LastUpdate (code 1): , while compiling: INSERT INTO groups(GroupType,GroupID,LastUpdate,IsAdmin,GroupName,GroupStatus) VALUES (?,?,?,?,?,?)
And when I check the schema again the column is missing.
H:\adt-bundle-windows-x86_64-20140702\sdk\platform-tools>sqlite3
SQLite version 3.8.10.2 2015-05-20 18:17:19
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .open mydb.db
sqlite> .fullschema
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE groups ( rowId INTEGER PRIMARY KEY,GroupID TEXT, GroupName TEXT,GroupStatus TEXT,IsAdmin TEXT, GroupType TEXT, IsPublic
TEXT);
/* No STAT tables available */
Any leads on this would be of great help.
onCreate() method of sqliteOpenHelpers called when the database is created for the first time. This is where the creation of tables and the initial population of the tables should happen.
I think first time when you created your database you don't include LastUpdate column. Later you included it.but your table is created first time.So when adb get same database version for your app it dose not update your database.
So try this
Change your databse version no. Or uninstall app from your phone and run it again.
If problem does not solve.Then please provide full code of your class in Question.

android initialize database install once

Im developing an app for Android and Im looking for a way to create a database table and initialize it but to do it only once when the app is installed or when its first time started. After the table is created and initialized for the first time I do not want this code to rune any more because it inserts a lot of data in to the table.
Haw can I do that?
Extend SQLiteOpenHelper
public class MyDB extends SQLiteOpenHelper {
Context c;
public MyDB(Context c) {
super(c, DB_NAME, null, DB_VERSION);
this.c=c;
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table "+DB_TABLE+" ( _id integer primary key autoincrement, "+COL_1+" text, "+COL_2+" text, "+COL_3+" text, "+COL_4+" integer, "+COL_5+" integer, "+COL_6+" text );");
}
#Override
public void onUpgrade(SQLiteDatabase db, int from, int to) {
Log.i("onUpgrade", "From Version "+from+" to version "+to);
switch(from) {
case 0:
db.execSQL("DROP TABLE IF EXISTS wine;");
db.execSQL("create table "+DB_TABLE+" ( _id integer primary key autoincrement, "+COL_1+" text, "+COL_2+" text, "+COL_3+" text, "+COL_4+" integer, "+COL_5+" integer, "+COL_6+" text );");
case 1:
db.execSQL("ALTER TABLE "+DB_TABLE+" ADD COLUMN "+COL_6+" text;"); //comment was not in the original database
break;
}
}
You need to create a class that is extends SQLLiteHelper and overwrite the onCreate() method to create your table and insert any rows. After this time, the database queries will not be executed unless you get a writable instance of it and pass in your own queries.
If you wanted to make changes to your app in the future, you would need to override the onUpgrade() method to make changes to your database.
Check if database is empty on every start of your app, if so insert your data, otherwise ignore.

Android SQLite Upgrade without losing data

I have created a SQLite database successfully and it works fine. However when the onUpgrade method is called, I'd like to do so without losing data. The app I'm developing is a quiz app. Simply, when the onCreate method is called I create and prepopulate a database with questions, answers etc. The last column is whether they have set the question as a favourite or not. What I would like to do is that when the onUpgrade method is called, I'd like to temporarily save that one column, drop the whole database, recreate it with any edits I've made to old questions and add any new questions then re-add back the questions that they set as favourites.
So one option I tried was the following:
db.execSQL("ALTER TABLE quiz RENAME TO temp_quiz");
onCreate(db);
db.execSQL("INSERT INTO quiz (favouries) SELECT favourites FROM temp_quiz");
db.execSQL("DROP TABLE IF EXISTS temp_quiz");
However this doesn't work owing to the fact INSERT INTO just adds new rows rather than replacing the existing rows. I have also tried REPLACE INTO, INSERT OR REPLACE INTO and
db.execSQL("INSERT INTO quiz (_id, favouries) SELECT _id, favourites FROM temp_quiz");
of which none work.
Currently I do have it set up to work by altering the name of the table, calling the onCreate(db) method and then setting up a cursor which reads each row and uses the db.update() method as shown below:
int place = 1;
int TOTAL_NUMBER_OF_ROWS = 500;
while (place < TOTAL_NUMBER_OF_ROWS) {
String[] columns = new String[] { "_id", ..........., "FAVOURITES" };
// not included all the middle columns
Cursor c = db.query("temp_quiz", columns, "_id=" + place, null, null, null, null);
c.moveToFirst();
String s = c.getString(10);
// gets the value from the FAVOURITES column
ContentValues values = new ContentValues();
values.put(KEY_FLAG, s);
String where = KEY_ROWID + "=" + place;
db.update(DATABASE_TABLE, values, where, null);
place++;
c.close();
}
However whilst this works it is extremely slow and will only get worse as my number of questions increases. Is there a quick way to do all this?
Thank you! P.S. Ideally it should only update the row if the row is present. So if in an upgrade I decide to remove a question, it should take this into account and not add a new row if the row doesn't contain any other data. It might be easier to get it to remove rows that don't have question data rather than prevent them being added.
changed it to:
db.execSQL("UPDATE new_quiz SET favourites = ( SELECT old_quiz.favourites
FROM old_quiz WHERE new_quiz._id = old_quiz._id) WHERE EXISTS
( SELECT old_quiz.favourites FROM old_quiz WHERE new_quiz._id = old_quiz._id)");
Which works :D
public class DataHelper extends SQLiteOpenHelper {
private static final String dbName="dbName";
private Context context;
private SQLiteDatabase db;
private final static int version = 1;
public static final String SurveyTbl = "CREATE TABLE SurveyTbl (SurveyId TEXT PRIMARY KEY, Idref TEXT, SurveyDate TEXT)";
public DataHelper(Context context) {
super(context, dbName, null, version);
this.db = getWritableDatabase();
this.context = context;
Log.i("", "********************DatabaseHelper(Context context)");
}
#Override
public void onCreate(SQLiteDatabase db) {
try {
db.execSQL(SurveyTbl);
} catch (Exception e) {
Log.i("", "*******************onCreate");
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
try {
db.execSQL("ALTER TABLE HandpumpSurveyTbl ADD COLUMN NalYozna TEXT");
} catch (Exception e) {
Log.i("", ""+e);
}
onCreate(db);
}
}
I didn't get to see your Quiz table schema, but I assume it has fields like "question", "answer", "favorites", and some kind of a unique primary key to identify each question, which I will just call rowId for now.
// after renaming the old table and adding the new table
db.execSQL("UPDATE new_quiz SET new_quiz.favorites = old_quiz.favorites where new_quiz.rowId = old_quiz.rowId");
That will update only the rows of the new quiz table that match the old quiz table, and set the favorites value from the old quiz table.
I assume you have some kind of a unique identifier to identify each question, so instead of the rowId above, you'll use that (question number or something).
For who don't know yet how to upgrade the version of the SQLite when upgrading the database schema for example, use the method needUpgrade(int newVersion)!
My code:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
if(newVersion>oldVersion){
db.execSQL(scriptUpdate);
db.needUpgrade(newVersion);
}
}
ALTER TABLE mytable ADD COLUMN mycolumn TEXT
In your onUpgrade method, it would look something like this:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
String upgradeQuery = "ALTER TABLE mytable ADD COLUMN mycolumn TEXT";
if (newVersion>oldVersion)
db.execSQL(upgradeQuery);
}
Example, how to drop a table and create a new table without losing data by using a temporary table:
db.execSQL("CREATE TEMPORARY TABLE temp_table (_id INTEGER PRIMARY KEY AUTOINCREMENT, col_1 TEXT, col_2 TEXT);");
db.execSQL("INSERT INTO temp_table SELECT _id, col_1, col_2 FROM old_table");
db.execSQL("CREATE TABLE new_table (_id INTEGER PRIMARY KEY AUTOINCREMENT, col_1 TEXT, col_2 TEXT, col_3 TEXT);");
db.execSQL("INSERT INTO new_table SELECT _id, col_1, col_2, null FROM temp_table");
db.execSQL("DROP TABLE old_table");
db.execSQL("DROP TABLE temp_table");

How to join two tables in SQLiteDatabase?

I need to know how to join 2 tables together. I am not sure how to do the joining of tables as I'm new to this.
I've created AnniversaryDBAdapter.class where I create 5 tables in one database. I just need to join 2 tables like join buddiesList table and likes table.
Below is the code of the AnniversaryDBAdapter.class
public class AnniversaryDBAdapter
{
private static final String DATABASE_NAME = "AllTables";
private static final int DATABASE_VERSION = 2;
private static final String CREATE_TABLE_BUDDIESLIST = " create table buddiesList(name_id integer primary key autoincrement, name text not null);";
private static final String CREATE_TABLE_LIKES = " create table likes(name_id integer primary key autoincrement,likes text not null);";
private static final String CREATE_TABLE_DISLIKES = " create table dislikes(name_id integer primary key autoincrement, dislikes text not null);";
private static final String CREATE_TABLE_EVENTS = "create table events(date_id integer primary key autoincrement, name_id text not null, date text not null, title_id text not null, starttime text not null, endtime text not null);";
private static final String CREATE_TABLE_TITLE = "create table titles(title_id integer primary key autoincrement, name text not null, image text not null);";
private final Context context;
private static final String TAG = "DBAdapter";
private DatabaseHelper DBHelper;
private SQLiteDatabase db;
public AnniversaryDBAdapter(Context ctx)
{
this.context = ctx;
DBHelper = new DatabaseHelper(context);
}
private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL(CREATE_TABLE_BUDDIESLIST);
db.execSQL(CREATE_TABLE_LIKES);
db.execSQL(CREATE_TABLE_EVENTS);
db.execSQL(CREATE_TABLE_TITLE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
Log.w(TAG, "Upgrading database from version "+oldVersion+" to "+newVersion+", which will destroy all old data");
onCreate(db);
}
}
public AnniversaryDBAdapter open() throws SQLException
{
this.db = this.DBHelper.getWritableDatabase();
return this;
}
public void close()
{
this.DBHelper.close();
}
}
Assuming we correct your table layout to something like this:
CREATE TABLE buddiesList(
_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name TEXT NOT NULL
);
CREATE TABLE likes (
_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
buddy_id INTEGER REFERENCES buddiesList(_id) ON DELETE CASCADE NOT NULL,
likes TEXT NOT NULL
);
Now, in your setup you can create a VIEW of the JOIN between buddiesList and likes, it will act like a normal table when selecting - you just can't update/delete or insert from it (without messing around with TRIGGERs of course).
CREATE VIEW buddyLikes AS
SELECT buddiesList.*, likes._id AS likes_id, likes.likes as likes
FROM buddiesList LEFT JOIN likes ON buddiesList._id=likes.buddy_id;
A View is created using execSQL - just like a table or trigger.
With a view you can select from a join between buddies and likes, returning all buddies and all their likes, like so:
SELECT * from buddyLikes;
which would return something like this:
_id name likes_id likes
1 |Ted |5 |Facebook
1 |Ted |4 |Murder
2 |Ed |1 |Beer
2 |Ed |2 |Cats
2 |Ed |3 |Stock-car racing
3 |Red |6 |Bananarama
BTW: If you want foreign-key support in your database you need to call execSQL
with:
PRAGMA foreign_keys = ON
in your SQLiteOpenHelper#onOpen(SQLiteDatabase db).
Write a query and run with SQLiteDatabase.rawQuery(sql, params).

Categories

Resources