I have two table(dic,learnDataTable) in a sqlite database in a android project.In learDataTable there are 5 rows only. My aim is to fetch 5 random data from dic table and update 5 rows of the learnDataTable with this fetched data.
N:B: the structure of dic and learnDataTable is similar and they have two field and these are word as string type and meaning as string type.
I tried like this.
// fetch 5 random data from dic table
String sql ="SELECT * FROM dic ORDER BY RANDOM() LIMIT 5" ;
Cursor mCur = mDb.rawQuery(sql, null);
if (mCur!=null)
{
mCur.moveToNext();
}
//now update learnDataTable
for (int i = 0; i < mCur.getCount(); i++)
{
mCur.moveToPosition(i);
String word = mCur.getString(0).toString();
String meaning = mCur.getString(1).toString();
String sql2 ="update learnDataTable set english='"+word+"',bangla='"+meaning+"'";
mDb.execSQL(sql2);
}
But i know it just update all rows each time. My aim to update learnDataTable with 5 random data from dic table.
How can i do that???
Check this:
//Clears learnDataTable:
mDb.execSQL("DELETE FROM learnDataTable");
//Insert 5 random rows from dic:
mDb.execSQL("INSERT INTO learnDataTable (english, bangla) SELECT english ,bangla FROM dic ORDER BY RANDOM() LIMIT 5");
Fast and simple!
Select out the unique rowid out from your dic table as well, as it's needed in the update statement.
// fetch 5 random data from dic table
String sql = "SELECT rowid, english ,bangla "
+ "FROM dic ORDER BY RANDOM() LIMIT 5";
...
// now update learnDataTable
for (int i = 0; i < mCur.getCount(); i++) {
mCur.moveToPosition(i);
int id = mCur.getInt(0);
String word = mCur.getString(1);
String meaning = mCur.getString(2);
String sql2 = "update learnDataTable set english='" + word
+ "',bangla='" + meaning + "'" + " WHERE rowid = " + id;
mDb.execSQL(sql2);
}
Related
In my android app I have an SQLite database. with this structure:
PrivateList(idList INTEGER PRIMARY KEY, name TEXT, creationDate TEXT, active INTEGER, deactivationDate TEXT);
PrivateProduct (idProduct INTEGER PRIMARY KEY, description TEXT, quantity INTEGER, active INTEGER, additionDate TEXT);
List_Product(idList INTEGER NOT NULL, idProduct INTEGER NOT NULL, PRIMARY KEY (idList, idProduct), FOREIGN KEY(idList) REFERENCES PrivateList(idList), FOREIGN KEY(idProduct) REFERENCES PrivateProduct(idProduct));
I have an autogenerator list and elements using for to try the app:
localDB = new LocalDB(this, "localBD", null, 1);
SQLiteDatabase sqLiteDatabase = localDB.getWritableDatabase();
if (sqLiteDatabase != null){
for (int i = 0; i < 10; i++){
String a = "List" + i;
String b = "Product" + i;
Log.i("execfor", "INSERT INTO PrivateList (name, creationDate, active, deactivationDate) " + " VALUES ('" + a + "', CURRENT_TIMESTAMP, 1, null);");
sqLiteDatabase.execSQL("INSERT INTO PrivateList (name, creationDate, active, deactivationDate) " + " VALUES ('" + a + "', CURRENT_TIMESTAMP, 1, null);");
sqLiteDatabase.execSQL("INSERT INTO PrivateProduct (description, quantity, active, additionDate) " + " VALUES ('" + b + "', 3, 1, CURRENT_TIMESTAMP);");
//sqLiteDatabase.execSQL("INSERT INTO List_Product (idList, idProduct) values ");//
}
}
But I can`t find the way to get rowIds from each list and product to insert both, idlist and idproduct, into List_Product.
Thank you in advance.
The main change to facilitate grabbing the id's would be to swap from using execSQL to using insert as insert returns the id of the inserted row, execsql does not.
A little more on this here Using execSQL for INSERT operation in Android SQLite.
However, I'm not sure if you can pass CURRENT_TIMESTAMP via a ContentValues and it would result getting the current timestamp as opposed to just setting the value to the literal CURRENT_TIMESTAMP. You could use DEFAULT CURRENT_TIMEPSTAMP in the respective column definitions (as I have in the code below).
I'd suggest that you would not want a link between every list/product permutation (that would be 100 rows for you 10 List rows and 10 Product rows) as in real life you would probably not have such a scenario rather you'd have some links between the two. So in the code below I've randomly created links.
First some code from the Database Helper (for my convenience named SO45449914) for performing the inserts:-
public long insertListRow(String name,
int active) {
ContentValues cv = new ContentValues();
cv.put(LISTNAME_COL,name);
cv.put(LISTACTIVE_COL,active);
cv.put(LISTDEACTIVATIONDATE_COL,"");
return this.getWritableDatabase().insert(PRIVATELISTTABLE,null,cv);
}
public long insertProductRow(String description,int quantity, int active) {
ContentValues cv = new ContentValues();
cv.put(PRODUCTDESCRIPTION_COL,description);
cv.put(PRODUCTQUANTITY_COL,quantity);
cv.put(PRODUCTACTIVE_COL,active);
return this.getWritableDatabase().insert(PRIVATEPRODUCTTABLE,null,cv);
}
public void insertListProductLink(long listid, long productid) {
ContentValues cv = new ContentValues();
cv.put(LISTPRODUCTLIST_COL,listid);
cv.put(LISTPRODUCTPRODUCT_COL,productid);
if (this.getWritableDatabase().insertOrThrow(LISTPRODUCTTABLE,null,cv) <0) {
//handle failed insert
}
}
Notes
- I've used class variables for all columns names.
- Columns that have the current time stamp get this via the default, so there is no need to have a cv.put for those columns.
In the activity is the following code :-
void doSO45449914() {
SO45449914 dbhelper = new SO45449914(this);
int loopcount = 10;
long[] listids = new long[loopcount];
long[] productids = new long [loopcount];
for (int i=0; i < 10; i++) {
listids[i] = dbhelper.insertListRow("a" + i,1);
productids[i] = dbhelper.insertProductRow("b" + i,3,1);
}
Cursor csra = dbhelper.getWritableDatabase().query(SO45449914.PRIVATELISTTABLE,
null,null,null,null,null,null
);
Cursor csrb = dbhelper.getWritableDatabase().query(SO45449914.PRIVATEPRODUCTTABLE,
null,null,null,null,null,null
);
Log.d("SO45449914","Number of rows in LIST TABLE = " + csra.getCount());
Log.d("SO45449914","Number of rows in PRODUCTS TABLE = " + csrb.getCount());
for (long aid: listids) {
Log.d("SO45449914","LIST ID from store = " + Long.toString(aid));
}
for (long bid: productids) {
Log.d("SO45449914","PRODUCT ID from store = " + Long.toString(bid));
}
for (long lid: listids) {
for (long prdid: productids) {
if ((Math.random() * 100) > 60) {
dbhelper.insertListProductLink(lid,prdid);
Log.d("SO45449914",
"Adding link between List id(" +
Long.toString(lid) +
") and product id(" +
Long.toString(prdid) +
")"
);
}
}
}
csra.close();
csrb.close();
}
Exlapnation
The first few lines prepare long arrays based upon the number of Lists and products to be created (same number of both). Integer loopcount determines how many.
The first loop, inserts Lists and Products which use the insert method storing the returned id in the respective array element.
Two Cursors are then created for obtaining row counts, which are then written to the log. The id's as stored in the arrays are output to the log.
Two nested loops are then invoked with Products being the inner (not that it matters) and randomly (about 40% of the time) a row will be inserted into the link table. I've assumed random but you always easily adjust the algorithm to follow a pattern. It's if ((Math.random() * 100) > 60) { that determines whether or not to insert a link.
The two Cursors are then closed.
Results
Here are screen shots of the resultant tables :-
PrivateList Table
PrivateProduct Table
List_Product Table
..... (44 rows in the List_Product table)
Well, this is what I did. Despite of the fact that there is a way do the same without so many rows in List_Product table; I'd like to understand the way. (Also I had problem in the for so it didnt do what I wanted exactly).
localDB = new LocalDB(this, "localBD", null, 1);
SQLiteDatabase sqLiteDatabase = localDB.getWritableDatabase();
if (sqLiteDatabase != null){
long idList;
long idProduct;
for (int i = 0; i < 10; i++){
String a = "List" + i;
String b = "Product" + i;
ContentValues contentValuesList = new ContentValues();
contentValuesList.put("name", a);
contentValuesList.put("active", 1);
contentValuesList.put("creationDate", "CreationDate");
contentValuesList.put("deactivationDate", "");
idList = sqLiteDatabase.insert("PrivateList", null, contentValuesList);
for (int j = 0; j < 10; j++){
ContentValues contentValuesProduct = new ContentValues();
contentValuesProduct.put("description", b);
contentValuesProduct.put("active", 1);
contentValuesProduct.put("quantity", 1);
contentValuesProduct.put("additionDate", "additionDdate");
idProduct = sqLiteDatabase.insert("PrivateProduct", null, contentValuesProduct);
ContentValues contentValuesListProduct = new ContentValues();
contentValuesListProduct.put("idList", idList);
contentValuesListProduct.put("idProduct", idProduct);
sqLiteDatabase.insert("List_Product", null, contentValuesListProduct);
}
I know it could be more efficient, but that it doesn't matter now.
This is the result in the database:
PrivateList:
with 10 rows
PrivateProduct:
with 100 rows.
List_Product:
The problem was that I didn't know the existance of sqlLiteDatabase.insert(...) method.
Thanks you all.
I am running a query in sqllite browser which gives the output fine.
But when i am running the query through Android's SqlLiteDatabase's rawQuery function it returns 3 rows for every original row
The query being -
select s.shout_id, u.user_id, u.image_id , u.firstname, u.lastname, s.shout_msg , i.user_id 'r_user_id' , i.image_id 'r_img_id', i.firstname 'r_firstname', i.lastname 'r_lastname', s.rec_time from shouts s left join users u
on s.user_id = u.user_id left join users i on s.reciever_id = i.user_id
where ((s.user_id =1 and s.reciever_id =2) or (s.user_id =2 and s.reciever_id =1) ) and s.shout_id < 5 order by s.shout_id desc limit 20;
The raw query code being in android -
public Cursor get_friend_shouts_less(String myid, String friend_id, long shout_id) {
open();
Log.d("ListView1", "get less Message myid friend_id shout_id: " + myid + " " + friend_id + " " + shout_id );
Cursor c = db.rawQuery("select s.shout_id, u.user_id, u.image_id , u.firstname, u.lastname, s.shout_msg , i.user_id 'r_user_id' , i.image_id 'r_img_id', i.firstname 'r_firstname', i.lastname 'r_lastname', s.rec_time from shouts s left join users u " +
"on s.user_id = u.user_id left join users i on s.reciever_id = i.user_id" +
" where ((s.user_id =? and s.reciever_id =?) or (s.user_id =? and s.reciever_id =?) ) and s.shout_id < ? order by s.shout_id desc limit 60;", new String[]{myid, friend_id, friend_id, myid , String.valueOf(shout_id)});
return c;
}
Glad it worked, now my official Answer:
A SQL LEFT JOIN Operation is equal to an karthesian product AxB, which can lead to rows wih the same content. In "simple": using GROUP BY merges those identical rows.
I have a table with events, and want to select all events which happen from three days ago. (The events do belong to categories which is a field in the Article table which has to description etc., but that works).
This is my code:
public List<Event> findByCategory(long catId, int start, int count) throws Exception {
String limit = "";
if (count > 0) limit = start + "," + count;
SQLiteQueryBuilder _QB = new SQLiteQueryBuilder();
_QB.setTables("Event e INNER JOIN Article a ON e.articleId=a.id");
String[] rows = _fields.keySet().toArray(new String[0]);
for (int i = 0; i < rows.length; i++) {
rows[i] = "e." + rows[i];
}
Cursor cursor = _QB.query(_db, rows, "date(e.startTime) > date('now','-3 days') AND EXISTS(SELECT * FROM CategoryArticleLink WHERE CategoryArticleLink.articleId = a.id AND EXISTS (SELECT * FROM Category WHERE Category.id = CategoryArticleLink.categoryId AND Category.id = '" + catId + "'))", null, null, null, "e.startTime ASC", limit);
List<Event> list = new ArrayList<>(cursor.getCount());
if (cursor.moveToFirst()) {
do {
Event item = getObject(cursor);
list.add(item);
} while (cursor.moveToNext());
}
cursor.close();
return list;
}
The resulting Query is:
SQLiteQuery: SELECT e.articleId, e.keynote, e.locationId, e.id, e.finishTime, e.startTime, e.languageCode, e.flag, e.lastUpdate FROM Event e INNER JOIN Article a ON e.articleId=a.id WHERE (date(e.startTime) > date('now','-3 days') AND EXISTS(SELECT * FROM CategoryArticleLink WHERE CategoryArticleLink.articleId = a.id AND EXISTS (SELECT * FROM Category WHERE Category.id = CategoryArticleLink.categoryId AND Category.id = '9'))) ORDER BY e.startTime ASC LIMIT 0,8
This returns an empty result set. However, if I take the date selection (date(e.startTime) > date('now','-3 days')) out of the query it returns all records as expected. So I must be doing something small wrong, but I just don't see what.
The field type on database generation is 'DATE', so that should be ok I expect.
The correct code in my setup is 'date(e.startTime / 1000, 'unixepoch') > date('now','-3 day')'. I use Date().getTime() to save the date/time as a long. But have uses a timestamp a 1000x larger then normal.
Moreover, the 'unixepoch' seems to be a needed addition in the date function.
Please let me know how to delete n-rows in android sqlite database. I used this code:
String ALTER_TBL ="delete from " + MYDATABASE_TABLE +
"where"+KEY_ID+"in (select top 3"+ KEY_ID +"from"+ MYDATABASE_TABLE+"order by _id );";
sqLiteDatabase.execSQL(ALTER_TBL);
But it shows an error.
03-21 13:19:39.217: INFO/Database(1616): sqlite returned: error code = 1, msg = near "in": syntax error
03-21 13:19:39.226: ERROR/Database(1616): Failure 1 (near "in": syntax error) on 0x23fed8 when preparing 'delete from detail1where_id in (select top 3_idfromdetail1order by _id );'.
String ALTER_TBL ="delete from " + MYDATABASE_TABLE +
" where "+KEY_ID+" in (select "+ KEY_ID +" from "+ MYDATABASE_TABLE+" order by _id LIMIT 3);";
there is no "top 3" command in sqlite I know of, you have to add a limit
watch out for spaces when you add strings together : "delete from" + TABLE + "where" = "delete frommytablewhere"
This approach uses two steps to delete the first N rows.
Find the first N rows:
SELECT id_column FROM table_name ORDER BY id_column LIMIT 3
The result is a list of ids that represent the first N (here: 3) rows. The ORDER BY part is important since SQLite does not guarantee any order without that clause. Without ORDER BY the statement could delete 3 random rows.
Delete any row from the table that matches the list of ids:
DELETE FROM table_name WHERE id_column IN ( {Result of step 1} )
If the result from step 1 is empty nothing will happen, if there are less than N rows just these will be deleted.
It is important to note that the id_column has to be unique, otherwise more than the intended rows will be deleted. In case the column that is used for ordering is not unique the whole statement can be changed to DELETE FROM table_name WHERE unique_column IN (SELECT unique_column FROM table_name ORDER BY sort_column LIMIT 3). Hint: SQLite's ROWID is a good candidate for unique_column when deleting on tables (may not work when deleting on views - not sure here).
To delete the last N rows the sort order has to be reversed to descending (DESC):
DELETE FROM table_name WHERE unique_column IN (
SELECT unique_column FROM table_name ORDER BY sort_column DESC LIMIT 3
)
To delete the Nth to Mth row the LIMIT clause can be extended by an OFFSET. Example below would skip the first 2 rows and return / delete the next 3.
SELECT unique_column FROM table_name ORDER BY sort_column LIMIT 3 OFFSET 2
Setting the LIMIT to a negative value (e.g. LIMIT -1 OFFSET 2) would return all rows besides the first 2 resulting in deletion of everything but the first 2 rows - that could also be accomplished by turning the SELECT .. WHERE .. IN () into SELECT .. WHERE .. NOT IN ()
SQLite has an option to enable the ORDER BY x LIMIT n part directly in the DELETE statement without a sub-query. That option is not enabled on Android and can't be activated but this might be of interest to people using SQLite on other systems:
DELETE FROM table_name ORDER BY sort_column LIMIT 3
It seems that you've missed some spaces:
"where"+KEY_ID+"in..
must be:
"where "+KEY_ID+" in...
Furthermore you need to use the limit statement instead of top:
I'll do:
db.delete(MYDATABASE_TABLE, "KEY_ID > "+ value, null);
you can try this code
int id;
public void deleteRow(int id) {
myDataBase.delete(TABLE_NAME, KEY_ID + "=" + id, null);
}
String id;
public void deleteRow(String id) {
myDataBase.delete(TABLE_NAME, KEY_ID + "=\" " + id+"\"", null);
}
It is a bit long procedure but you can do it like this
first get the ids column of table from which which you want to delete certain values
public Cursor KEY_IDS() {
Cursor mCursor = db.rawQuery("SELECT KEYID " +
" FROM MYDATABASE_TABLE ;", null);
if (mCursor != null)
{
mCursor.moveToFirst();
}
return mCursor;
}
Collect it in an array list
ArrayList<String> first = new ArrayList<String>();
cursor1 = db.KEY_IDS();
cursor1.moveToFirst();
startManagingCursor(cursor1);
for (int i = 0; i < cursor1.getCount(); i++) {
reciv1 = cursor1.getString(cursor1
.getColumnIndex(DBManager.Player_Name));
second.add(reciv1);
}
and the fire delete query
for(int i = 0 ;i<second.size(); i++)
{
db.delete(MYDATABASE_TABLE KEYID +"=" + second.get(i) , null);
}
Delete first N (100) rows in sqlite database
Delete from table WHERE id IN
(SELECT id FROM table limit 100)
You can make use of the following mode: (in addition to the response provided by "zapl").
**DELETE FROM {Table-X} WHERE _ID NOT IN
(SELECT _ID FROM {Table-X} ORDER BY _ID DESC/ASC LIMIT (SELECT {Limit-Column} FROM {SpecificationTable}) );**
Where {Table-X} refers to the table you want to delete, _ID is the main unique-column
DESC/ASC - Based on whether you want to delete the top records or the last records, and finally in the "LIMIT" clause, we provide the "n" factor using another query, which calls in the {Limit-Column} from {SpecificationTable}: Which holds the value against which you want to delete them.
Hope this helps out someone.
Happy Coding.
I am querying several columns in a table for some words (essentially querying m text columns whether they contain n terms which are entered by the user), and I want to rank these rows by how many matches occur.
So I have something like this query :
SELECT *, (COLUMN1 LIKE '%TERM1%') + (COLUMN1 LIKE '%TERM2%') + ... + (COLUMN1 LIKE '%TERMN%') + (COLUMN2 LIKE '%TERM1%') + ... + (COLUMNM LIKE '%TERMN%') AS SCORE
FROM TABLE_NAME
WHERE COLUMN1 LIKE '%TERM1%' OR ... OR COLUMNM LIKE '%TERMN%'
ORDER BY SCORE DESC LIMIT 200;
But this query does not seem to work all the time, sometimes all the results seem to have score 0, even when there are matches. Can anybody suggest what the problem is? I suspect it might be something to do with the type of result of LIKE operator and the type of score column.
Also, is there some better way of doing the same thing without generating this verbose query?
yes there another way using code
try this
long cnt = countdata("COLUMN1 LIKE %TERM1%")
:
public Long countdata(String whereClause) {
long count = 0;
Cursor c = mDb.rawQuery("SELECT count(*) FROM TABLENAME WHERE " + whereClause, null);
int numRows = c.getCount();
c.moveToFirst();
for (int i = 0; i < numRows; ++i) {
Log.i("Count", c.getString(0));
count = c.getLong(0);
c.moveToNext();
}
c.close();
return Long.valueOf(count);
}