syntax error while compiling sqlite - android

I'm trying to make a new table for my database with sqlite:
String CREATE_ARCHIVE_TABLE =
"CREATE TABLE {0} ({1} INTEGER PRIMARY KEY AUTOINCREMENT," +
" {2} TEXT NOT NULL, {3} TEXT NOT NULL, {4} TEXT NOT NULL, {5} INTEGER);";
db.execSQL(MessageFormat.format(CREATE_ARCHIVE_TABLE,AItext.TABLE_NAME,AItext._ID,
AItext.TITLE,AItext.MESSAGE,AItext.DATE,AItext.TYPE));
with the interface:
public interface AItext extends BaseColumns {
String TABLE_NAME = "table_name";
String TITLE = "title";
String MESSAGE = "message";
String DATE = "date";
String TYPE = "type";
String[] COLUMNS = new String[]
{ _ID, TITLE, MESSAGE, DATE, TYPE };
}
but I have the following exception and I can't see the error
android.database.sqlite.SQLiteException: near "INTEGER": syntax error: ,
while compiling: CREATE TABLE archive_contacts_name (_id INTEGER PRIMARY KEY
AUTOINCREMENT, message INTEGER, name TEXT NOT NULL, phone TEXT NOT NULL,
check INTEGER, note TEXT NOT NULL);

As #aim has said, CHECK is in fact a SQLite Keyword that cannot be used as a column name.
A CHECK constraint may be attached to a column definition or specified as a table constraint. In practice it makes no difference. Each time a new row is inserted into the table or an existing row is updated, the expression associated with each CHECK constraint is evaluated and cast to a NUMERIC value in the same way as a CAST expression. If the result is zero (integer value 0 or real value 0.0), then a constraint violation has occurred. If the CHECK expression evaluates to NULL, or any other non-zero value, it is not a constraint violation. The expression of a CHECK constraint may not contain a subquery.
CHECK constraints have been supported since version 3.3.0. Prior to version 3.3.0, CHECK constraints were parsed but not enforced.

Related

Android - Change a column type in SQLite database dynamically at runtime

I have an application, where I am detecting the type of a particular column at run-time, on page load. Please refer the below code:
public String fncCheckColumnType(String strColumnName){
db = this.getWritableDatabase();
String strColumnType = "";
Cursor typeCursor = db.rawQuery("SELECT typeof (" + strColumnName +") from tblUsers, null);
typeCursor.moveToFirst();
strColumnType = typeCursor.getString(0);
return strColumnType;
}
The above method simply detects the type of column with column Name 'strColumnName'. I am getting the type of column in this case.
Now, I want to change the column type to TEXT if I am receiving INTEGER as the column type. For this, I tried the below code:
public String fncChangeColumnType(String strColumnName){
db = this.getWritableDatabase();
String newType = "";
Cursor changeCursor = db.rawQuery("ALTER TABLE tblUsers MODIFY COLUMN " + strColumnName + " TEXT", null);
if (changeCursor != null && changeCursor.moveToFirst()){
newType = changeCursor.getString(0);
}
return newType;
}
But while executing the 'fncChangeColumnType' method, I am getting this error, android.database.sqlite.SQLiteException: near "MODIFY": syntax error (code 1): , while compiling: ALTER TABLE tblUsers MODIFY COLUMN UserID TEXT
NOTE: I also replaced 'MODIFY' with 'ALTER', but still getting the same error.
Please check if this is the right method to change the type dynamically.
Please respond back if someone has a solution to this.
Thanks in advance.
In brief, the solution could be :-
Do nothing (i.e. take advantage of SQLite's flexibility)
you could utilise CAST e.g. CAST(mycolumn AS TEXT) (as used below)
Create a new table to replace the old table.
Explanations.
With SQLite there are limitations on what can be altered. In short you cannot change a column. Alter only allows you to either rename a table or to add a column. As per :-
SQL As Understood By SQLite - ALTER TABLE
However, with the exception of a column that is an alias of the rowid column
one defined with ?? INTEGER PRIMARY KEY or ?? INTEGER PRIMARY KEY AUTOINCREMENT or ?? INTEGER ... PRIMARY KEY(??) (where ?? represents a valid column name)
you can store any type of value in any type of column. e.g. consider the following (which stores an INTEGER, a REAL, a TEXT, a date that ends up being TEXT and a BLOB) :-
CREATE TABLE IF NOT EXISTS example1_table (col1 BLOB);
INSERT INTO example1_table VALUES (1),(5.678),('fred'),(date('now')),(x'ffeeddccbbaa998877665544332211');
SELECT *, typeof(col1) FROM example1_table;
The result is :-
As such is there a need to change the column type at all?
If the above is insufficient then your only option is to create a new table with the new column definitions, populate it if required from the original table, and to then replace the original table with the new table ( a) drop original and b)rename new or a) rename original, b) rename new and c) drop original)
e.g. :-
DROP TABLE IF EXISTS original;
CREATE TABLE IF NOT EXISTS original (mycolumn INTEGER);
INSERT INTO original VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(0);
-- The original table now exists and is populated
CREATE TABLE IF NOT EXISTS newtable (mycolumn TEXT);
INSERT INTO newtable SELECT CAST(mycolumn AS TEXT) FROM original;
ALTER TABLE original RENAME TO old_original;
ALTER TABLE newtable RENAME TO original;
DROP TABLE IF EXISTS old_original;
SELECT *,typeof(mycolumn) FROM original;
The result being :-
i think the sql query statement is wrong ,try
ALTER TABLE tblUsers MODIFY COLUMN id TYPE integer USING (id::integer);
instead of id use column name....
hope this helps....
EDIT:
"ALTER TABLE tblUsers MODIFY COLUMN "+strColumnName+" TYPE integer USING ("+strColumnName+"::integer);"

android.database.sqlite.SQLiteException: no such column: personal (code 1):

I have a table created by this sql command ->
CREATE TABLE messages( id integer primary key autoincrement, senderNum String, messagebody String, label String );
In this Table I have a row having senderNum equal to 123.In order to apply label to it i call method which looks like this ->
public void ApplyLabel(String senderNum){
SQLiteDatabase db = this.getWritableDatabase();
Cursor res = db.rawQuery("update messages set label=personal where senderNum=" + senderNum,null);
}
where the variable senderNum have value 123.Now when this method is called it throws error like this ->
android.database.sqlite.SQLiteException: no such column: personal (code 1): , while compiling: update messages set label=personal where senderNum=123
I don't know why it gives this error ??
You are missing the string delimiters (') surrounding your string value.
As it's now, you are comparing a column named label to another column named personal, which doesn't exist.
Try:
Cursor res = db.rawQuery("update messages set label='personal' where senderNum=" + senderNum,null);
If you want to use a variable, you can concatenate the string like so:
Cursor res = db.rawQuery("update messages set label='" + strPersonal + "' where senderNum=" + senderNum,null);

Android SQLite Join Query

I'm creating an app as a learning tool and am having difficulty with join queries.
I have a database with two tables- horses and covers- declared as follows;
private static final String HORSES_CREATE = "create table horses (_id integer primary key autoincrement, "
+ "name text not null, type integer not null, birthDate text not null, vaccineDate text not null, "
+ "inFoal integer not null, notes text not null);";
The 'type' field refers to stallion, mare, gelding etc and is selected from a spinner (populated from an XML String array).
private static final String COVERS_CREATE = "create table covers (_id integer primary key autoincrement, "
+ "stallionName integer not null, mareName integer not null, firstCoverDate text not null, lastCoverDate text not null, "
+ "scan14Date text not null, scan28Date text not null, foalingDate text not null, inFoal integer not null, notes text not null);";
stallionName is actually stored as the _id field of the horse from the horse table. It is selected from a spinner that only displays horses whose type defined as 'Stallion' in the horses table. (The same applies for Mare).
I have a class 'DatabaseHelper' to create and upgrade the tables, and each table has its own adapter class 'horsesDbAdapter' and 'coversDbAdapter' that contains the methods to add, edit and delete entries, and relevant queries. (fetchAllHorses(), fetchHorse(long rowId) )
eg:
public Cursor fetchAllHorses() {
return mDb.query(DATABASE_TABLE,
new String[] { KEY_ROWID, KEY_NAME, KEY_TYPE, KEY_BIRTHDATE,
KEY_VACCINEDATE, KEY_INFOAL, KEY_NOTES }, null, null,
null, null, null);
}
(It's all adapted from the Android notepad example)
I have the contents of the covers table displayed in a listview (just showing the stallionName and mareName). But as those fields just contain the unique reference to the horses table all that is displayed is the fairly uninformative _id field.
My question is; how can I get the relevant name for the horses to display in the listView? I've read up on join queries etc but get lost when I try implement them. I assume I have to join on horses._id and covers.stallionName (then make an almost-identical one for MareName) but I can't find a concrete example of how to do this.
Please let me know if any additional information/ code is needed.
Any help would be greatly appreciated, thankyou in advance.
EDIT:
I have made stallionName and mareName foreign keys referencing (_id) in the horses table, but am still unsure how and where to implement the join query; should it be in the horsesDbAdapter, coversDbAdapter or the coversList class? (coversList is the class that creates and populates the listView)
The covers table declaration now reads;
private static final String COVERS_CREATE = "create table covers (_id integer primary key autoincrement, "
+ "stallionName integer not null, mareName integer not null, firstCoverDate text not null, lastCoverDate text not null, "
+ "scan14Date text not null, scan28Date text not null, foalingDate text not null, inFoal integer not null, notes text not null," +
"FOREIGN KEY (stallionName) REFERENCES horses (_id), FOREIGN KEY (mareName) REFERENCES horses (_id));";
I'm a newbie to Android and SQLLiteHelper and was wondering about the same thing.
After reading this post, I found that the method to define joins between tables is done with the SQLLiteQueryBuilder.setTables method. See the reference here
I got this from this blog
Hope this helps pointing readers in the right direction.
I've managed to get it working. For anyone else who may have a similar problem I'll try detail what I did.
As #deceiver stated I should have made stallionName and mareName foreign keys referencing horses (see Edit).
In the coversList class (the class that implements the listView) I just needed to get an instance of the database and use a rawQuery to implement the SQL code directly (It may be possible to do it with Query but I'm not sure how)
The added code is as follows;
private Cursor coversCursor;
private void fillData() {
db = (new DatabaseHelper(this).getReadableDatabase());
coversCursor = db.rawQuery("SELECT horses1.name AS stallionNameText, covers.*, horses2.name AS mareNameText FROM horses horses1 JOIN covers ON horses1._id = covers.stallionName JOIN horses horses2 ON horses2._id = covers.MareName",
null);
startManagingCursor(coversCursor);
// Create an array to specify the fields we want to display in the list
// (the renamed fields from the above query)
String[] from = new String[] { "stallionNameText", "mareNameText" };
// and an array of the fields we want to bind those fields to (in this
// case just text1)
int[] to = new int[] { R.id.rowStallionName, R.id.rowMareName };
// Now create a simple cursor adapter and set it to display
SimpleCursorAdapter covers = new SimpleCursorAdapter(this,
R.layout.covers_list_row, coversCursor, from, to);
setListAdapter(covers);
}
FillData() is then called in the onCreate() method. Then just close the db in the onDestroy method.
(Selecting all columns from the covers table seems wasteful here but I will eventually show these columns in the listView aswell. I just wanted to answer this before continuing coding).
A tutorial I found helpful was http://coenraets.org/blog/android-samples/androidtutorial/
I had issues with the SQL query as there are 2 foreign keys referencing the same table and I wanted the listView to display both the stallion name and mare name, so had to join two horses table to a covers table. I just needed to rename the tables in the FROM section of the SQL query. Hopefully the above code is clear. If not, I found the following useful; http://www.bryantwebconsulting.com/blog/index.cfm/2005/3/11/join_a_table_to_itself_in_sql
Sorry if this explanation is too specific to my (unusual) example.
Thanks for reading.

why does db.insert() giving the sqliteconstraintexception error 19 constraint failed

I have read most of the questions related to this exception but none of them are clear or indicative of why db.insert would throw this error. It was working fine without errors until I manually deleted the db from DDMS. Following is my SQLiteOpenHelper code:
public class LoginSQLiteOpenHelper extends SQLiteOpenHelper {
public static final String DB_NAME = "logincredentials.sqlite";
public static final int DB_VERSION_NUMBER = 1;
public static final String DB_TABLE_NAME = "credentials";
public static final String USERNAME = "user_name";
public static final String PASSWORD = "password";
private static final String DB_CREATE_SCRIPT = "create table " + DB_TABLE_NAME +
"( _id integer primary key autoincrement," +
USERNAME + " text not null, " +
PASSWORD + " text not null );" ;
public LoginSQLiteOpenHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION_NUMBER);
}
#Override
public void onCreate(SQLiteDatabase aSqliteDB) {
Logger.d("Create", "Creating the database...");
aSqliteDB.execSQL(DB_CREATE_SCRIPT);
}
}
My code for inserting the values is:
ContentValues contentValues = new ContentValues();
contentValues.put(LoginSQLiteOpenHelper.USERNAME, loginId);
contentValues.put(LoginSQLiteOpenHelper.PASSWORD, password);
database.insert(LoginSQLiteOpenHelper.DB_TABLE_NAME, null, contentValues);
This is why it occurred to me. If you declare one of your column name type as UNIQUE in your Create Table query in Database and try to insert a non unique variable, it invokes SQLiteConstraintException error.
A UNIQUE constraint is similar to a PRIMARY KEY constraint, except that a single table may have any number of UNIQUE constraints. For each UNIQUE constraint on the table, each row must feature a unique combination of values in the columns identified by the UNIQUE constraint. As with PRIMARY KEY constraints, for the purposes of UNIQUE constraints NULL values are considered distinct from all other values (including other NULLs). If an INSERT or UPDATE statement attempts to modify the table content so that two or more rows feature identical values in a set of columns that are subject to a UNIQUE constraint, it is a constraint violation. Source - http://www.sqlite.org/lang_createtable.html
I have read pretty much all forums looking for an exact reason for the occurrence of this exception. However, nowhere it clearly states so. However, by means of this code of mine, I can explain why it ocurred for me.
The code snippet I provided, is actually flawless. I am doing exactly what is required to do a db.insert().
However, i figured out the exception in 2 steps.
1. first time when i inserted values, I did not insert a value for the column Password.
2. second time, I added a value for column for Password, but due to incorrect passing of values it was null.
hence, I deduced from this exercise, that no column are allowed null values. You must initialize them with some value.
Please feel free to comment/add or correct me if I am wrong. I would like anyone else running into this issue to be clear on it as there are no good documentation on this exception.

SQLiteException - no such table

Im getting this error when i try to access my View
I've built my database/View using this
CREATE TABLE Boxer(
BoxerId INTEGER PRIMARY KEY AUTOINCREMENT,
Firstname NVARCHAR(50) NOT NULL,
Lastname NVARCHAR(50) NOT NULL
);
CREATE TABLE Match(
MatchId INTEGER PRIMARY KEY AUTOINCREMENT,
BoxerA INTEGER NOT NULL FOREIGN KEY REFERENCES Boxer(BoxerId),
BoxerB INTEGER NOT NULL FOREIGN KEY REFERENCES Boxer(BoxerId),
MatchDate date NOT NULL DEFAULT GETDATE(),
NumberOfRounds INTEGER NOT NULL DEFAULT 12
);
CREATE TABLE Round(
RoundId INTEGER PRIMARY KEY AUTOINCREMENT,
MatchId INTEGER NOT NULL FOREIGN KEY REFERENCES Match(MatchId),
BoxerA INTEGER NOT NULL DEFAULT 0,
BoxerB INTEGER NOT NULL DEFAULT 0,
Position INTEGER NOT NULL
);
/*
Building a view which dislpays matches with boxers names and total scores
*/
CREATE VIEW MatchDetail AS
SELECT Match.MatchId, A.BoxerId AS IdA, B.BoxerId AS IdB, A.Firstname + ' ' + A.Lastname AS NameA, B.Firstname + ' ' + B.Lastname AS NameB,
(SELECT SUM(R.BoxerA) AS Score FROM Round AS R WHERE (R.MatchId = Match.MatchId)) AS ScoreA,
(SELECT SUM(R.BoxerB) AS Score FROM Round AS R WHERE (R.MatchId = Match.MatchId)) AS ScoreB,
Match.MatchDate, Match.NumberOfRounds
FROM Boxer AS A INNER JOIN Match ON A.BoxerId = Match.BoxerA INNER JOIN Boxer AS B ON Match.BoxerB = B.BoxerId
I've pretty much built my app so far using the notepad example so I then call my DbHelper
Cursor MatchesCursor = mDbHelper.fetchAllMatchDetails();
This then calls the query
public Cursor fetchAllMatchDetails(){
return mDb.query(VIEW_MATCHDETAIL, new String[] {
"MatchId"
}, null, null, null, null, null);
}
VIEW_MATCHDETAIL is defined as a string = "MatchDetail"
and it's here where it crashes saying
no such table MatchDetail: while compiling SELECT MatchId FROM MatchDetail
anyone had this problem before?
You have some beautiful SQL there. Unfortunately only the first line of sql will be executed in SQLiteDatabase.execSQL. The rest will be ignored silently (convenient eh?). Split up the statements manually like this:
https://github.com/browep/fpt/blob/master/src/com/github/browep/nosql/NoSqlSqliteOpener.java
or if you like to keep your sql in a separate file, try this:
String sqlText = getSqlText();
for(String sqlStmt : sqlText.split(";"))
myDb.execSQL(slqStmt + ";");
What stands out to me is the use of datatypes like NVARCHAR(50). SQLite only has a very simple set of datatypes. I'm surprised it doesn't throw an exception when you install the app. Try using simply TEXT instead.
If you cannot access a database that you know you have initialized, try passing the Context from the Activity that created the table to the class trying to query the table. Use that Context as part of your connection initialization.

Categories

Resources