The Android API docs appear to suggest that the limit clause to provide when querying a SQLite database is a string.
This does not make much sense to me.
Presumably, it is converted internally to an integer?
Or are there other issues involved here?
I think they key thing to consider is that the parameter isn't solely for the single 1st part (see expr1 below) but for the entire LIMIT Clause.
This clause can be as as simple as just a single integer, but it can also be relatively complex; the full syntax of a LIMIT Clause is :-
LIMIT expr1 OFFSET (or ,) expr2; see - SELECT
Where :-
expr1 should resolve to an integer specifying the maximum number of rows to be returned and
expr2 is an integer that specifies the offset (where 1 is the 1st) from the start of the potential rows to be returned.
either expression could, at least in theory, be a subquery e.g.
String limit_clause = "(SELECT numbertoshow FROM types WHERE id = (random() & 1)+1)";
P.S. not saying this is a useful example rather it is an example that works and is for illustration of a complex LIMIT clause and as such an example of why a String as opposed to an Integer is the more flexible/useful parameter type.
The complete SQL used for testing the above was :-
/*
DROP TABLE IF EXISTS basetable;
CREATE TABLE IF NOT EXISTS basetable (basename TEXT);
INSERT INTO basetable VALUES('test001');
INSERT INTO basetable VALUES('test002');
INSERT INTO basetable VALUES('test003');
INSERT INTO basetable VALUES('test004');
INSERT INTO basetable VALUES('test005');
INSERT INTO basetable VALUES('test006');
INSERT INTO basetable VALUES('test007');
INSERT INTO basetable VALUES('test008');
INSERT INTO basetable VALUES('test009');
INSERT INTO basetable VALUES('test010');
INSERT INTO basetable VALUES('test011');
INSERT INTO basetable VALUES('test012');
DROP TABLE IF EXISTS types;
CREATE TABLE IF NOT EXISTS types (id INTEGER PRIMARY KEY, typename TEXT, numbertoshow INTEGER);
INSERT INTO types VALUES(null,'type001',3);
INSERT INTO types VALUES(null,'type002',4);
*/
SELECT * FROM basetable LIMIT (SELECT numbertoshow FROM types WHERE id = (random() & 1)+1);
Note commented out statements are commented out as they are just needed the once.
Related
I need to retrieve the id of the row inserted just now. ie, i have a table for words and a table for meaning. i need the wordId of the word i insert in the table for words and that wordId is used for inserting the meaning in meaning table. Can anyone help me out??
I thought i could use trigger and tried the trigger:
"CREATE TRIGGER IF NOT EXISTS word_insert_trigger AFTER INSERT ON tb_words BEGIN select NEW.word_id from tb_words; END;"
like this. i tried this in sqlite dbbrowser. but it didn't work out.
i need the row id when i insert a row like this :"insert into tb_words(word_name) values('test');"
How can i do that without using "SELECT last_insert_rowid()"? like in the following link:
How to retrieve the last autoincremented ID from a SQLite table?
No need for a trigger. Use the SQliteDatabase insert method. It returns the id (as a long) (more correctly it returns the rowid and assuming that the word_id column has been defined as an alias of the rowid column, then the returned value will be the value assigned to the word_id column).
An alias of the rowid column is defined if word_id INTEGER PRIMARY KEY is coded (the AUTOINCREMENT key may be used BUT in generally should not be used).
You may wish to read SQLite AUTOINCREMENT and/or Rowid Tables
Instead of something like :-
db.execsql("insert into tb_words(word_name) values('test');");
You would use something like :-
ContentValues cv = new ContentValues();
cv.put("word_name","test");
long word_id = db.insert("tb_words",null,cv);
1.which data type should be used to store data like group=AB+ ?
E/SQLiteLog: (1) near "group": syntax error SQLiteDatabase:
Error inserting
district=jhapa phone=9843284985 name=Tom group=AB+
My table is in this format
CREATE TABLE IF NOT EXISTS `Doners` (\n" +
"\t`name`\tTEXT,\n" +
"\t`phone`\tNUMERIC,\n" +
"\t`group`\tBLOB,\n" +
"\t`district`\tTEXT\n" +
");";
For Android you can either use
- native SQL via the SQLiteDatabase execSQL method
- the SQLiteDatabase convenience insert family of methods :-
insert (effectively INSERT OR IGNORE)
insertOrThrow (standard INSERT)
insertWithOnConflict
SQLiteDatabase - insert
So assuming that you want to insert :-
Tom into the name column,
9843284985 into the phone column,
AB+ into the group column,
NOTE that group is an SQLite keyword and therefore cannot be used and will result in a syntax error, unless it is enclosed SQL As Understood By SQLite - SQLite Keywords
jhapa
And that the variable db is an instantiated instance of the SQliteDatabase class then :-
you could use :-
db.execSQl("INSERT INTO `Doners` VALUES('Tom',9843284985,'AB+','jhapa')");
noting that a value must be provided for all the defined columns and that the values should be in the order that the columns were defined in.
or you could use :-
db.execSQL("INSERT INTO Doners (district,phone,name,`group`) VALUES ('jhapa','9843284985','Tom','AB+')");
Here you specify the columns into which the values will be placed, you can specify them in what order you like (values will be inserted according to the order), you can also omit columns (dependant upon the column definition)
Defining a column as NOT NULL would require a column and value. However, if a DEFAULT value has been defined as well as NOT NULL then the column can be omitted.
you could use the insert convenience method like :-
ContentValues cv = new ContentValues();
cv.put("phone","9843284985");
cv.put("name","Tom);
cv.put("`group`","AB+");
cv.put("district","jhapa");
long rowid = db.insert("Doners",null,cv);
rowid will be the rowid of the inserted row (a unique identifier of the row) or if no row was inserted then -1.
the convenience method :-
it builds the SQL on your behalf
protects against SQL injection
encloses values accordingly
suitable encodes byte[]'s into the the x'ff00fe.......' used by SQL.
returns the rowid (executes a query using last_insert_rowid()).
in regards to :-
which data type should be used to store data like group=AB+ ?
Due to SQLite's flexibility it probably does not matter what type is assigned to the column. That is with the exception of the rowid or an alias of the rowid (the_column INTEGER PRIMARY KEY makes the_column an alias of the rowid column) any type of data can be stored in any type of column and to further expand on the flexibility type can be virtually anything (keywords and other syntactically confusing values excepted).
As such CREATE TABLE mytable (mycolumn RUMPLESTILTSKIN) is valid (column has numeric affinity). see - Datatypes In SQLite Version 3
In my Android app, I create a FULLTEXT table like this:
CREATE VIRTUAL TABLE products USING fts3 (
_id integer PRIMARY KEY,
product_name text NOT NULL,
...
)
And I add this index:
CREATE INDEX product_name_index ON products (product_name)
The app populates the table with various products, each with a unique _id value.
However, when I then try to insert an already-existing product ID (using an _id value that is already in the table, but with a different product_name value) like this:
long rowId = db.insertOrThrow("products", null, contentValues);
a new row is added to the table (with a brand new rowId value returned)!
I expected the insertOrThrow command to fail, so where am I going wrong? Is it something to do with the fact that it's a FULLTEXT table or could the index I specified on the product_name column be messing things up somehow?
I read this section about INTEGER PRIMARY KEY, but unfortunately I'm none the wiser.
Update
When I try to perform the same operation on a standard (non-FULLTEXT) table, then the insertOrThrow command results in the expected SQLiteConstraintException.
I think the issue might be that an FTS table has the concept of a docid and a rowid column and specifying null for the docid results in that being given a value.
as per :-
There is one other subtle difference between "docid" and the normal
SQLite aliases for the rowid column.
Normally, if an INSERT or UPDATE
statement assigns discrete values to two or more aliases of the rowid
column, SQLite writes the rightmost of such values specified in the
INSERT or UPDATE statement to the database.
However, assigning a
non-NULL value to both the "docid" and one or more of the SQLite rowid
aliases when inserting or updating an FTS table is considered an
error. See below for an example.
1.3. Populating FTS Tables
I am using SQLite Database for my application. I have 4 columns- Student_Name,Student_Enroll, Student_Mob, Student_Address in my database. Now I can add new record if and only if one of four column value is different or all values are different. If all column values are same then no new record should be generated.
Can you please guide me to solve this issue?
To enforce that a set of columns must be unique, add a UNIQUE constraint:
create table Students (
/* ID INTEGER PRIMARY KEY, */
Student_Name TEXT,
Student_Enroll TEXT,
Student_Mob TEXT,
Student_Address TEXT,
UNIQUE (Student_Name, Student_Enroll, Student_Mob, Student_Address)
);
This allows new rows only if at least one of the four columns has a different value.
With a plain INSERT, attempting to insert a duplicate row will result in an error. If you simply want to ignore it instead, use INSERT OR IGNORE:
INSERT OR IGNORE INTO Students ...;
Despite of set your column as UNIQUE you also need to resolve the conflict created on each column when you try to insert new data.
To do so, define the behavior to solve the conflict:
"CREATE TABLE table (your columns here...(UNIQUE unique colums here...) ON CONFLICT REPLACE);"
During Create Database line insert UNIQUE ...for each column to insert only unique record.
Solution 1: (Simple)
Define all columns as unique:
create table TableName (id integer primary key autoincrement,
Student_Name text not null unique,
Student_Enroll text not null unique,
Student_Mob text not null unique);
You can add Student_Address as well, if you need to
Solution 2: (bit complex)
Use AND Operator with WHERE clause
INSERT INTO TableName (Student_Name, Student_Enroll, Student_Mob)
SELECT varStudentName, varStudentEnroll, varStudentMob
WHERE NOT EXISTS(SELECT 1 FROM TableName WHERE Student_Name = varStudentName OR Student_Enroll = varStudentEnroll OR Student_Mob = varStudentMob );
//If a record already contains a row, then the insert operation will be ignored.
You can find more information at the sqlite manual.
Live Example:
Open SQLite Online
Paste following code:
INSERT INTO demo (id,name,hint)
SELECT 4, 'jQuery', 'is a cross-platform JavaScript library designed to simplify the client-side scripting of HTML'
WHERE NOT EXISTS(SELECT 1 FROM demo WHERE name = 'jQuery' OR hint = 'is a cross-platform JavaScript library designed to simplify the client-side scripting of HTML' );
SELECT * from demo
Hit RUN
This won't insert 4th record and if you modify both values of WHERE clause then record will be inserted.
I am trying to insert data into two table with unique id being generated in Table1 and use the generate unique id in Table2.
Example:
I want to insert empl_no and empl_name into table 1 and table 2. After inserting the empl_no in Table1 it will auto-generate an id for that row. This id would need to be used to on Table2 to insert the empl_name.
Table 1
empl_id | empl_no
-----------------
1 | e00001
Table 2
empl_id | empl_name
-------------------
1 | Andy
What I have in mind is to insert empl_no into Table1 to then do a select to get the last row to retrieve the empl_id. Then use the empl_id to insert into Table2.
Is there a better to do this? It looks inefficient because each time to insert a data it will need to select from the Table just to get the generated unique id.
If you define empl_id as INTEGER PRIMARY KEY in Table1 (optionally with AUTOINCREMENT, but it's better not to use it unless you explicitly need it) then you won't need the extra SELECT statement. The insert() method will return its value.
From the SQLite documentation:
If a table contains a column of type INTEGER PRIMARY KEY, then that
column becomes an alias for the ROWID. You can then access the ROWID
using any of four different names, the original three names described
above or the name given to the INTEGER PRIMARY KEY column. All these
names are aliases for one another and work equally well in any
context.
And from the Android documentation:
public long insert (String table, String nullColumnHack, ContentValues values)
Returns the row ID of the newly inserted row, or -1 if an error occurred.