SQLite on Android: Different result set at Runtime vs. SQLite Administrator - android

I am building an Android app with an internal SQLite DB.
Here is the schema:
CREATE TABLE IF NOT EXISTS [tblImageVideoLink] (
[LinkID] INTEGER NOT NULL PRIMARY KEY,
[ImageID] INTEGER UNIQUE NOT NULL,
[VideoID] INTEGER NULL
);
CREATE TABLE IF NOT EXISTS [tblImages] (
[ID] INTEGER PRIMARY KEY NOT NULL,
[ImageName] VARCHAR(50) NOT NULL,
[ImageDescription] VARCHAR(100) NULL,
[Page] INTEGER NULL
);
CREATE TABLE IF NOT EXISTS [tblPages] (
[ID] INTEGER NOT NULL PRIMARY KEY,
[PageName] VARCHAR(30) NULL
);
CREATE TABLE IF NOT EXISTS [tblVideos] (
[ID] INTEGER NOT NULL PRIMARY KEY,
[VideoName] VARCHAR(150) NOT NULL,
[VideoDescription] VARCHAR(100) NULL,
[VideoType] VARCHAR(10) NULL
);
CREATE INDEX IF NOT EXISTS [IDX_TBLIMAGEVIDEOLINK_IMAGEID] ON [tblImageVideoLink](
[ImageID] DESC,
[VideoID] DESC
);
CREATE INDEX IF NOT EXISTS [IDX_TBLIMAGES_PAGE] ON [tblImages](
[Page] DESC
);
Here's the relevant data I have in the tables:
INSERT INTO tblImages (ID, ImageName, Page) VALUES (1, 'Beach.jpg', 1);
INSERT INTO tblImages (ID, ImageName, Page) VALUES (2, 'Bowling.jpg', 1);
INSERT INTO tblImages (ID, ImageName, Page) VALUES (3, 'Car.jpg', 1);
INSERT INTO tblVideos (ID, VideoName) VALUES (2, 'Bowling.3gp');
INSERT INTO tblVideos (ID, VideoName) VALUES (3, 'Car.3gp');
INSERT INTO tblImageVideoLink (LinkID, ImageID, VideoID) VALUES (1, 2, 2);
INSERT INTO tblImageVideoLink (LinkID, ImageID, VideoID) VALUES (2, 3, 3);
INSERT INTO tblPages (ID, PageName) VALUES (1, 'Misc');
I am trying to run this query to get all the images with a certain page, and their related videos:
SELECT DISTINCT I.ID AS 'Image ID', I.ImageName, V.ID AS 'Video ID', V.VideoName
FROM tblImages I
LEFT JOIN tblImageVideoLink L ON L.VideoID=V.ID
LEFT JOIN tblVideos V ON L.ImageID=I.ID
WHERE I.Page=1;
When I test it in SQLite Administrator, I am getting the desired result set, which is:
When I test it in the App (or in SQLiteSpy) I am getting a different result set:
I have tried everything I know, including GROUP BY, removing the DISTINCT, different JOIN types, etc.
BTW, SQLiteSpy writes at the bottom: SQLite 3.7.8 while SQLite Administrator writes SQLite 3.5.1. I don't know if it matters.
Please help, and also kindly explain why there's a difference between two SQLite tools...

What you see in SQLLite Admin is (considering your output) same as
SELECT DISTINCT(I.ImageName), V.VideoName
What you actual seeing in app is (considering your output) same as
SELECT DISTINCT(I.ImageName, V.VideoName)
Try brackets

My dear friend and DBA helped me spot my issue. Here's the working query to JOIN the two tables and get the data set I wanted:
SELECT DISTINCT I.ID AS 'Image ID', I.ImageName, V.ID AS 'Video ID', V.VideoName
FROM tblImages I
LEFT JOIN tblImageVideoLink L ON L.ImageID=I.ID
LEFT JOIN tblVideos V ON L.VideoID=V.ID
WHERE I.Page=1;
Thank you all for trying to help.

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);"

sqlite - conditional replace and insert

working environment: using sqlite for android os. Doing bulk insert.
consider the following schema or sqlfiddle:
CREATE TABLE employee_data
(
id varchar(20) primary key,
name varchar(20),
dept varchar(20),
updation_date varchar(30)
);
INSERT INTO employee_data
(id, name, dept, updation_date)
VALUES
("1", "john", "tech", "2017-04-30");
INSERT INTO employee_data
(id, name, dept, updation_date)
VALUES
("2", "john2", "tech", "2017-05-01");
While adding an entry to employee_data table, following conditions must be met:
if given entry does not already exists (compared on the basis of id), then add it.
if the id already exists; then check the 'updation_date' column -
if updation_date of entry to be added is later compare to the one that already exists - then update the row.
else do nothing.
Example:
I)
need to insert ("1", "john", "management", "2017-05-01")
as there is already an entry with id = 1, check for updation_date;
now since "2017-05-01" is more recent data - update the row.
so ouput - ("1", "john", "management", "2017-05-01")
II)
need to insert ("3", "steve", "management", "2017-06-01")
as no entry with id= 3 in employee_data, directly add this one
output: ("3", "steve", "management", "2017-06-01") is added.
III)
("2", "john2", "tech", "2017-04-01");
as id=2 row exists with more recent updation_date ("2017-05-01")
do nothing.
I have tried to search but could not find solution. I can't figure out how can I use insert into select statement. Or whether I can use select from dual.
I remember using merge in oracle for similar use case.
Note:
updation_date column can be changed to timestamp format or date format for ease in comparing it.
Thanks.
SQLite is an embedded database; you are supposed to implement complex logic in your application:
void conditionalReplaceAndInsert(ContentValues cv)
{
String oldDate = DatabaseUtils.stringForQuery(db,
"SELECT updation_date FROM employee_data WHERE id = ?",
new String[]{ cv.getAsString("id") });
if (oldDate.equals(""))
db.insertOrThrow("employee_data", null, cv);
else if (oldDate.compareTo(cv.getAsString("updation_date")) < 0)
db.update("employee_data", cv, "id = ?",
new String[]{ cv.getAsString("id") });
else
; // do nothing
}

SQLite query doesn't work as expected

I have a problem with an SQLite Query and can't figure it out. These are my table:
CREATE TABLE Exercise
(
e_id int auto_increment primary key,
name varchar(20)
);
CREATE TABLE PersonalList
(
p_id int auto_increment primary key,
name varchar(20)
);
CREATE TABLE Exercise_Personal_List
(
e_id_m int auto_increment primary key,
p_id_m int
);
INSERT INTO Exercise
(e_id, name)
VALUES
('1', 'exercise1'),
('2', 'exercise2'),
('3', 'exercise3'),
('4', 'exercise4'),
('5', 'exercise5'),
('6', 'exercise6');
INSERT INTO PersonalList
(p_id, name)
VALUES
('1', 'list1'),
('2', 'list2'),
('3', 'list3');
INSERT INTO Exercise_Personal_List
(e_id_m, p_id_m)
VALUES
('2', '1'),
('4', '1'),
('6', '1'),
('1', '2');
Exercise table: a collection of exercises
PersonalList table: a collection of list
Exercise_Personal_List: a reference to which Exercise is part of which Exercise_Personal_List
I'm trying to get a list of Exercises that are not yet added to a specific list. E.g. the ones that are not added to List 1. My query:
select * from Exercise
where e_id not in (
select e_id from Exercise_Personal_List
where p_id_m like '1'
)
The result is empty. I don't see the error in the query. The correct result should be 1, 3, 5.
Btw, I'm using http://sqlfiddle.com to evaluate this stuff. It's faster for testing :)
Thanks for your help!
I think you mean to be doing the following query where the second instance of e_id has been changed to e_id_m:
select * from Exercise
where e_id not in (
select e_id_m from Exercise_Personal_List
where p_id_m like '1'
)
There is a little mess up in the creation - you shouldn't use auto_increment in the joining table:
CREATE TABLE Exercise_Personal_List
(
e_id_m int,
p_id_m int
);
And the selection should be:
select * from Exercise
where e_id not in (
select e_id_m as e_id from Exercise_Personal_List
where p_id_m like '1'
)

Error in SQlite syntax i dont know whats wrong

I wonder what's wrong with my sql syntax.Its working on mysql but for sqlite gives me error.
CREATE TABLE IF NOT EXISTS `points` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) CHARACTER SET latin1 NOT NULL,
`longitude` double NOT NULL,
`latitude` double NOT NULL,
`radius` double NOT NULL,
`image` blob NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_persian_ci AUTO_INCREMENT=4;
INSERT INTO `points` (`id`, `name`, `longitude`, `latitude`, `radius`, `image`)
VALUES (1, 'Isfahan, Iran', 51.678314, 32.65036, 0.064486,
0xffd8ffe000104a46494600010001009600960000fffe001f4c45414420546563686e6f6c6f6769657320496e632e2056312e303100ffdb008400100b0c0e0c0a100e0d0e1211101318281a181616183123251d283b343e3d3a34393841495d4f414558463839516f52586063696a693f4e737b72667a5d676964011112121815182f1a1a2f644339436464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464ffc4003000000203010000000000000000000000000001020304050101010101010100000000000000000000000102030405ffc20011
It should be AUTOINCREMENT as one word.
You dont require this statement: ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_persian_ci AUTO_INCREMENT=4; which is MySQL specific. Further more, if you are setting the autoincrement value to start from 5, then you shouldn't be inserting an id of value equal to 1.
You do not seem to have a closing bracket after the insert statement.
You should instead try:
CREATE TABLE IF NOT EXISTS `points` (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`name` varchar(50) CHARACTER SET latin1 NOT NULL,
`longitude` double NOT NULL,
`latitude` double NOT NULL,
`radius` double NOT NULL,
`image` blob NOT NULL
);
INSERT INTO `points` (`id`, `name`, `longitude`, `latitude`, `radius`, `image`)
VALUES (1, 'Isfahan, Iran', 51.678314, 32.65036, 0.064486,
0xffd8ffe000104a46494600010001009600960000fffe001f4c45414420546563686e6f6c6f6769657320496e632e2056312e303100ffdb008400100b0c0e0c0a100e0d0e1211101318281a181616183123251d283b343e3d3a34393841495d4f414558463839516f52586063696a693f4e737b72667a5d676964011112121815182f1a1a2f644339436464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464ffc4003000000203010000000000000000000000000001020304050101010101010100000000000000000000000102030405ffc20011);
There could be more fixes required as well. Back tick though recognized by SQLite, is a MySQL specific quoting.

Android - relational database SQLite with multiple tables

I'm trying to build a database using 21 tables each bind with constraints. I have implemented the database in PHPmyAdmin and then download the structure script to import in my Android SQLite database.
But I would like to know what are the good practices in building relational databases with many tables in Android, and how to create them.
currently I have a class implementing SQLiteOpenHelper:
public class SqlSig extends SQLiteOpenHelper {
#Override
public void onCreate(SQLiteDatabase db) {
for(int i = 0; i != ConfigBDD.requetes.length; i++){
db.execSQL(ConfigBDD.requetes[i]);
}
}
}
ConfigBDD.requetes[i] fetch a string array containing tables creation requests and constraints requests. This code doesn't work at all, and logCat show an error with the PRIMARY KEY instruction:
05-29 15:13:51.992: E/Database(8187): Failure 1 (near "KEY": syntax error) on 0x15c4b8
when preparing 'CREATE TABLE IF NOT EXISTS `arret` ( `id` int(11) NOT NULL , `id_externe`
varchar(10) DEFAULT NULL, `id_pid` int(11) NOT NULL, `nom` varchar(50) NOT NULL,
`description` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `id_pid` (`id_pid`) )
DEFAULT CHARSET=utf8 =1 ;'.
I am pretty sure there are other ways to create this database but did not found any explanations about multi tables Android SQLite database creation...
Your:
CREATE TABLE IF NOT EXISTS `arret` (
`id` int(11) NOT NULL ,
`id_externe` varchar(10) DEFAULT NULL,
`id_pid` int(11) NOT NULL,
`nom` varchar(50) NOT NULL,
`description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `id_pid` (`id_pid`))
DEFAULT CHARSET=utf8 =1 ;
should probably look something like this if you want it to work in SQLite.
CREATE TABLE IF NOT EXISTS arret (
id INTEGER PRIMARY KEY NOT NULL ,
id_externe TEXT DEFAULT NULL,
id_pid INTEGER NOT NULL,
nom TEXT NOT NULL,
description TEXT
);
followed by a CREATE INDEX for your id_pid which is what KEY implies in MySQL.

Categories

Resources