Android exception in sql query that runs fines in DB Browser - android

When running the following query on Android
select *
from EICRChecklistItems
where (Sect, S_Sect, SS_Sect) in (
select Sect, S_Sect, SS_Sect
from EICRCheckList
where Version=2018
order by id
)
order by id
I get the exception:
android.database.sqlite.SQLiteException: near ",": syntax error (code
1)
Columns Sect, S_Sect and SS_Sect are all defined as integer.
But when running on DB Browser against a copy of the same database it executes correctly
Any pointers as to what may be causing this would be greatly appreciated.
private var EICR_CHECK_ITEMS_TABLE = "EICRChecklistItems"
private var EICR_CHECKLIST_TABLE = "EICRCheckList"
val cursor1: Cursor = writableDatabase.rawQuery(
"select * from $EICR_CHECK_ITEMS_TABLE where (Sect, S_Sect, SS_Sect) in (select Sect, S_Sect, SS_Sect from $EICR_CHECKLIST_TABLE where Version='2018' order by id) order by id", null)

Since your SQLite's version is prior to 3.15.0 and you can't use ROW VALUES, you can write your query with EXISTS instead of the operator IN:
SELECT ei.*
FROM EICRChecklistItems ei
WHERE EXISTS (
SELECT 1 FROM EICRCheckList el
WHERE el.Version = 2018
AND el.Sect = ei.Sect AND el.S_Sect = ei.S_Sect AND el.SS_Sect = ei.SS_Sect
)
ORDER BY ei.id
Note that the ORDER BY clause that you had inside the subquery in your code is actually useless.

Related

OrmLite query for date in joined table

I'm trying to build a query like this with ormLite:
SELECT `classA`.*
FROM `classA`
LEFT JOIN `classB` ON `classA`.`idField` = `classB`.`fkField`
WHERE `classB`.`dateField` >= '2015-11-16';
The dateField on classB looks like this:
#DatabaseField
private Date dateField;
So the date is persisted in ormLite's default format (e.g '2012-07-13 00:00:00.000000')
This is my approach in ormLite:
QueryBuilder<ClassA, Long> qbA = mDbHelper.getClassADao().queryBuilder();
QueryBuilder<ClassB, Integer> qbB = mDbHelper.getClassBDao().queryBuilder();
qbClassB.where().ge("dateField", new DateTime().minusDays(100).toDate());
qbA.leftJoin(qbB);
List<ClassA> list = qbA.query();
LogCat:
D/BaseMappedStatement: prepared statement 'SELECT `classA`.* FROM `classA` LEFT JOIN `classB` ON `classA`.`idField` = `classB`.`fkField` WHERE `classB`.`dateField` >= ? ' with 1 args
D/StatementExecutor: query of 'SELECT `classA`.* FROM `classA` LEFT JOIN `classB` ON `classA`.`idField` = `classB`.`fkField` WHERE `classB`.`dateField` >= ? ' returned 0 results
The raw query works fine and returns the desired results.
The ormLite query returns an empty resultList.
Does anyone have any idea of what I'm doing wrong?

android sqlite query "!=" multiple whereargs [duplicate]

I have a rather big query that is returning data when executed outside android while returning nothing when executed within android.
I split the query in several pieces and determined that the union was ok.
I tried on a smaller set of data with the same behavior.
I've tested with different hardware and API versions.
I'm using the rawQuery method with constant values.
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#rawQuery(java.lang.String, java.lang.String[])
This query was meant to replace a FULL OUTER JOIN which is not currently supported.
SELECT IFNULL(stype, gtype) AS type, IFNULL(sdate, gdate) AS date, IFNULL(sroute, groute) AS route FROM (
SELECT sp.type AS stype, sp.date AS sdate, -1 AS gtype, gp.date AS gdate, sp.route AS sroute, gp.route AS groute
FROM Sensor_Point AS sp LEFT JOIN GPS_Point AS gp ON gp._id IS NULL AND sp.sent=0 AND sp.route=gp.route AND sp.route=1
UNION ALL
SELECT sp.type AS stype, sp.date AS sdate, -1 AS gtype, gp.date AS gdate, sp.route AS sroute, gp.route AS groute
FROM GPS_Point AS gp LEFT JOIN Sensor_Point AS sp ON sp._id IS NULL AND gp.sent=0 AND sp.route=gp.route AND gp.route=1
) WHERE route=1 ORDER BY date ASC LIMIT 255
Any hints would be greatly appreciated.
Update:
Look's like the problem is finally with the query parameters, if I set it this way:
String[] args = new String[3];
args[0] = args[1] = args[2] = "1";
Cursor data dataBase.rawQuery(SELECT_POINTS, args);
It doesn't work, while it works when hardcoding values directly in the query.
Cursor data = dataBase.rawQuery(SELECT_POINTS, null);
In the Android database API, all query parameters are strings.
(This is a horrible design mistake.)
Your query corresponds to:
... AND sp.route='1'
Try to convert the parameter strings back into a number like this:
... AND sp.route = CAST(? AS INT)
or just put the number directly into the query string.

Cursor column index changes from phone to phone

My application allows a user to call the most recent number that was called out. By hitting the "Call" button with an empty text box it will grab the latest Outgoing number in my ORM database. The issue however happens on only some phones.
When I pull my data I do so with the following code:
Dao<RecentCallsInfo, Integer> dao = null;
if (getActivity() instanceof MainActivity) {
MainActivity main = (MainActivity) getActivity();
dao = main.getDatabaseHelper().getRecentDataDao();
}
QueryBuilder<RecentCallsInfo, Integer> qb = dao.queryBuilder();
qb.orderBy(RecentCallsInfo.RECENT_COLUMN_ID, false);
qb.where().eq(RecentCallsInfo.RECENT_COLUMN_CALL_TYPE, "Outgoing");
// when you are done, prepare your query and build an iterator
CloseableIterator<RecentCallsInfo> iterator = dao.iterator(qb.prepare());
// get the raw results which can be cast under Android
AndroidDatabaseResults results = (AndroidDatabaseResults)iterator.getRawResults();
Cursor c = results.getRawCursor();
if(c.moveToFirst()){
if(!c.getString(RecentQuery.COLUMN_NUM).isEmpty()){
System.out.println("Recent Record: \n Name:" + c.getString(RecentQuery.COLUMN_NAME) +
"\nNum:" + c.getString(RecentQuery.COLUMN_NUM) + "\nNumType:" + c.getString(RecentQuery.COLUMN_NUM_TYPE)+
"\nCallType:" + c.getString(RecentQuery.COLUMN_CALL_TYPE));
etcalle.setText(c.getString(RecentQuery.COLUMN_NUM));
}
}
//RecentQuery.COLUMN_NAME = 5
//RecentQuery.COLUMN_NUM = 6
//RecentQuery.COLUMN_NUM_TYPE = 0
//RecentQuery.COLUMN_CALL_TYPE = 2
When I debug my c Cursor, it gives me these columns with these values
[recentNumberType, recentCallCost, recentCallType, recentCallerID, recentDate, recentName, recentNumber, _id]
Name:anthony
Num:(111) 111-1111
NumType:Mobile
CallType:Outgoing
When I get my c Cursor on another phone I get
[recentCallCost, recentCallType, recentCallerID, recentDate, recentName, recentNumber, recentNumberType, _id]
Name:(111) 111-1111
Num:Mobile
NumType:FREE
CallType:1867
So when I try and pull my data by index I get different values. Why does this happen? Both phones are Nexus 5 and on 4.4.2.
Any insight on this would be great. Thanks!
Columns can "change". For example, consider this case.
Version 1 of an app creates the T table, with columns A, C
In version 2, you want to change the structure of the database. So you add the B column to your "create table" scripts. In new devices, this table will have columns A, B, C.
However, in the onUpgrade() part, you just add column B (via ALTER TABLE), and the structure will end up as A, C, B.
In general it's a bad idea to use fixed ("integer") column indexes, unless you also specify which columns you want (i.e. not using SELECT *). Using getColumnIndex() (outside the loop) is safer.

Android development with sqlite: query result shouldn't be empty

I have a rather big query that is returning data when executed outside android while returning nothing when executed within android.
I split the query in several pieces and determined that the union was ok.
I tried on a smaller set of data with the same behavior.
I've tested with different hardware and API versions.
I'm using the rawQuery method with constant values.
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#rawQuery(java.lang.String, java.lang.String[])
This query was meant to replace a FULL OUTER JOIN which is not currently supported.
SELECT IFNULL(stype, gtype) AS type, IFNULL(sdate, gdate) AS date, IFNULL(sroute, groute) AS route FROM (
SELECT sp.type AS stype, sp.date AS sdate, -1 AS gtype, gp.date AS gdate, sp.route AS sroute, gp.route AS groute
FROM Sensor_Point AS sp LEFT JOIN GPS_Point AS gp ON gp._id IS NULL AND sp.sent=0 AND sp.route=gp.route AND sp.route=1
UNION ALL
SELECT sp.type AS stype, sp.date AS sdate, -1 AS gtype, gp.date AS gdate, sp.route AS sroute, gp.route AS groute
FROM GPS_Point AS gp LEFT JOIN Sensor_Point AS sp ON sp._id IS NULL AND gp.sent=0 AND sp.route=gp.route AND gp.route=1
) WHERE route=1 ORDER BY date ASC LIMIT 255
Any hints would be greatly appreciated.
Update:
Look's like the problem is finally with the query parameters, if I set it this way:
String[] args = new String[3];
args[0] = args[1] = args[2] = "1";
Cursor data dataBase.rawQuery(SELECT_POINTS, args);
It doesn't work, while it works when hardcoding values directly in the query.
Cursor data = dataBase.rawQuery(SELECT_POINTS, null);
In the Android database API, all query parameters are strings.
(This is a horrible design mistake.)
Your query corresponds to:
... AND sp.route='1'
Try to convert the parameter strings back into a number like this:
... AND sp.route = CAST(? AS INT)
or just put the number directly into the query string.

How can I reset a autoincrement sequence number in sqlite

How to update table sqlite_sequence in Ormlite ? I just need update seq. How can I get that table via ORMLite ?
EDIT
I can't find ORLite tool to do this, so instead I use simple sqlite query. In my class extends OrmLiteSqliteOpenHelper I use SQLiteDatabase to make that update.
EDIT2 ;)
In my project I persist class Lesson and class WeekDefinition.
class Lesson{
#DatabaseField(generatedId=true)
private int id;
...
}
class WeekDefinitions{
#DatabaseField(generatedId=true)
private int id;
#DatabaseField(foreign=true, columnName="lesson_id")
private Lesson lesson;
...
}
Now , when I add new lessons, id is increment. For example
id = 1 Math
id = 2 English
id = 3 Medicine
and in weekDefinition :
id = 1 lesson_id = 1 nr = 20
id = 2 lesson_id = 1 nr = 22
id = 3 lesson_id = 2 nr = 32
...
id = 12 lesson_id = 3 nr = 3
SQLite add this row into sqlite_sequence ( when use autoincrement )
rowId = 1 name = lesson seq = 3
rowId = 2 name = weekDefinition seq = 12
Now, I delete all rows from tables Lesson and WeekDefinition. Lesson and WeekDef are empty after that, but sqlite_sequence is still the same. And this is problem because id in table lesson start from value 4 ( seq from sqlite_sequence for lesson and add 1 ) :
id = 4 Math
id = 5 English
id = 6 Medicine
and weekDefinition
id = 13 lesson_id = 1 nr = 20
id = 14 lesson_id = 1 nr = 22
id = 15 lesson_id = 2 nr = 32
and for lesson id = 4 , Math i should get weekDefinitios, but in weekDefinitions lessons_id has value only from 1 to 3
And this is my problem. I need "reset" sqlite_sequence table ( or there is better solution ?)
Building on Marcos Vasconcelos' answer:
UPDATE sqlite_sequence SET seq = (SELECT MAX(col) FROM Tbl) WHERE name="Tbl"
This query will set seq to the largest value in the col identity column in the Tbl table, so there is no risk of violating constraints.
Inside your .db file there's an table called sqlite_sequence
Each row has two columns
name which is the name of the table
seq a integer indicating the current last value at this table
You can update it to 0
But beware if your table use this id as the unique identifier.
UPDATE SQLITE_SEQUENCE SET SEQ= 'value' WHERE NAME='table_name';
If you want to issue general database commands in ORMLite, you can use the updateRaw method. See the javadocs. There is also executeRaw for other commands.
lessonDao.updateRaw("delete from 'lesson';");
lessonDao.updateRaw("delete from sqlite_sequence where name='lesson';");
weekDefinitionDao.updateRaw("delete from 'weekdefinition';");
weekDefinitionDao.updateRaw(
"delete from sqlite_sequence where name='weekdefinition';");
You could also drop and recreate the table as well:
TableUtils.dropTable(WeekDefinition.class);
TableUtils.dropTable(Lesson.class);
TableUtils.createTable(Lesson.class);
TableUtils.createTable(WeekDefinition.class);
I think the real question is why is your application depending on this database internal number? It really shouldn't care.
How about not displaying the number at all so it can be 1 or 1001 and your application won't matter?
You could also never remove the lessons at all but maybe add a hidden boolean field. So if they get re-added, the hidden field could be set to false and Math would still be at id #1.
This worked for me in my database : (I Set the id before one, then after deleting one row, when I add new data row again, the auto increment serial remain ok ) :
public void updateSerialNumber ( long memberId){
String query = "UPDATE SQLITE_SEQUENCE SET SEQ= '"+(memberId-1)+"' WHERE NAME='"+ReportBigHelper.TABLE_MEMBER+"'";
database.execSQL(query);
}

Categories

Resources