I'm using SQLite in Android (minSdkVersion: 15). I have table like this:
I'm trying to get list of last inserted rows with trainingId as a parameter. For example, I'd like to get list of last inserted rows with trainingId = 1 and the result should be:
13---5---1
14---5---1
15---5---1
or if trainingId = 2, then:
10---4---2
11---4---2
12---4---2
I tried something like this:
SELECT * FROM table_name JOIN (SELECT MAX(trainingDoneId) AS trainingDoneId FROM table_name GROUP BY treningId) USING (trainingDoneId)
and
SELECT * FROM table_name WHERE trainingDoneId IN (SELECT MAX(trainingDoneId) FROM table_name GROUP BY 1)
but in both cases I get this error:
android.database.sqlite.SQLiteException: aggregate functions are not allowed in the GROUP BY clause (code 1)
Any suggestions?
Please fire below query it will help you,
SELECT * FROM table_name where trainingId = 1 AND trainingDoneId in (select max(trainingDoneId) from table_name where trainingId = 1)
SELECT id, MAX(trainingDoneId), trainingId FROM table_name WHERE trainingId = 1 ORDERBY id
Try with this solution
Related
I have an application that makes quite a lot of selects, listing its results and allowing the user edit certain values.
The core of my question is if its possible to improve my queries or not given the following query in SQLite:
"SELECT X.data1, X.data2, count(X.id_X) as Quantity_Itens,
(select count(*) from Table2 where id_X=X.id_X) local_Table2,
(select count(*) from Table3 inner join Table2 on Table3.id_Table2 = Table2.id where Table3.id_X=X.id_X and type=1) Quantity_Type1,
(select count(*) from Table3 inner join Table2 on Table3.id_Table2 = Table2.id where Table3.id_X=X.id_X and type=2) Quantity_Type2,
(select count(*) from Table4 where id_X = X.id_X) Quantity_Other,
(select count(*) from Table2 where id_X = X.id_X and status <10) Total_Data FROM Table1 X where (X.type_item = 2 or X.type_item = 4 or X.type_item = 6 or X.type_item = 8) and X.ative = 1 and id_local != 0 group by X.id_X order by X.Alias1"
I am not sure if using promisses will improve in any way this, as I need all those datas before allowing the user to take control again.
Also, may or may not be relevant:
OS: Android 4+
Frameworks: Ionic1, AngularJS, Cordova
In your query there are 5 subqueries executed for each of the rows of Table1.
Only one of them accesses only once 1 table.
2 of them access the same table twice and 2 of them access 2 joined tables twice.
This means there are multiple scans through the same tables for each of the rows of Table1.
Also you are aggregating inside Table1, with GROUP BY id_X, but you have in the SELECT list 2 columns: data1 and data2, which are not included in the GROUP BY clause. This means that the returned values of these columns are arbitrary.
And what is that column Alias1? There is no such column among the returned columns of the query.
Anyway, I suggest that you aggregate first in each table, or join of tables and then join to Table1.
Like this:
SELECT t1.data1,
t1.data2,
t1.Quantity_Items,
t2.local_Table2,
t3.Quantity_Type1,
t3.Quantity_Type2,
t4.Quantity_Other,
t2.Total_Data
FROM (
-- The values returned for data1, data2 and Alias1 will be arbitrary
SELECT id_X, data1, data2, Alias1, COUNT(*) Quantity_Items
FROM table1
GROUP BY id_X
) t1
INNER JOIN (
SELECT id_X, COUNT(*) local_Table2, SUM(status < 10) Total_Data
FROM Table2
GROUP BY id_X
) t2 ON t2.id_X = t1.id_X
INNER JOIN (
SELECT t3.id_X, SUM(type = 1) Quantity_Type1, SUM(type = 2) Quantity_Type2
FROM Table3 t3 INNER JOIN Table2 t2
ON t3.id_Table2 = t2.id
GROUP BY t3.id_X
) t3 ON t3.id_X = t1.id_X
INNER JOIN (
SELECT id_X, COUNT(*) Quantity_Other
FROM Table4
GROUP BY id_X
) t4 ON t4.id_X = t1.id_X
WHERE t1.type_item IN (2, 4, 6, 8)
AND t1.active = 1 AND t1.id_local <> 0
ORDER BY t1.Alias1
I am building my first android app where I am trying to sync mysql data to sqlite in android. I have two tables in mysql and both gets synced properly into android sqlite. The first table is as follows:
id ProjectName
1 RA_Tesco
2 RA_Coors
3 RA_JWNT
The second table is as follows:
id pid Outlet Add1
1 1 Tesco XYZ
2 1 Tesco ABC
3 2 Coors NBC
The PID in second table references to id of first table. How can I subset the second table based on PID value derived from id of first table. I know it is pretty straight forward in php or mysql or even in Python or R. However, fetching the id based on string and referencing the same in the second table seems quite tricky in Android. My codes so far:
sqLiteDatabase = sqLiteHelper.getWritableDatabase();
clickedId = getIntent().getExtras().get("clickedId").toString();
When I toast clickedId, I get the correct string, for example, RA_Tesco.
cursor = sqLiteDatabase.rawQuery("SELECT * FROM "+SQLiteHelper.TABLE_NAME1+" where pid = 1"+"", null);
The above code also renders the correct set of records from the sqlite table. I am struggling with integrating them both. I tried the following:
String pid;
sqLiteDatabase = sqLiteHelper.getWritableDatabase();
clickedId = getIntent().getExtras().get("clickedId").toString();
pid = sqLiteDatabase.rawQuery( "select id from "+sqLiteHelper.TABLE_NAME+" where projectName = "+clickedId+"", null );
I am getting incompatible types error.
This is what worked for me:
clickedId = getIntent().getExtras().get("clickedId").toString();
cursor = sqLiteDatabase.rawQuery("SELECT * FROM "+SQLiteHelper.TABLE_NAME1+" where pid = (select id from "+SQLiteHelper.TABLE_NAME+ " where ProjectName = '"+clickedId+"'"+")", null);
I just followed the same MySQL principle of nesting queries. The above code roughly reads as follows:
select * from table2 where pid = (select id from table1 where projectname="xyz");
1) Try put your query to single quote
2) rawQuery returns Cursor, not String
So,
Cursor pidCursor = sqLiteDatabase.rawQuery( "select id from "+sqLiteHelper.TABLE_NAME+" where projectName = '"+clickedId+"'", null );
If you want to get the corresponding rows from the 2nd table when you pass as an argumnent the value of a ProjectName (I guess this is clickedId although its name is id?), create a statement like this:
String sql =
"select t2.* from " + SQLiteHelper.TABLE_NAME1 +
" t2 inner join " + SQLiteHelper.TABLE_NAME +
" t1 on t1.id = t2.pid where t1.ProjectName = ?";
This joins the 2 tables and returns all the columns of the 2nd table.
The execute rawQuery() by passing clickedId as a parameter, which is the proper way to avoid sql injection:
Cursor cursor = sqLiteDatabase.rawQuery(sql, new String[] {clickedId});
I have a query with a subquery that returns multiple rows.
I have a table with lists and a table with users. I created a many-to-many table between these two tables, called list_user.
LIST
id INTEGER
list_name TEXT
list_description TEXT
USER
id INTEGER
user_name TEXT
LIST_USER
id INTEGER
list_id INTEGER
user_id INTEGER
My query with subquery
SELECT * FROM user WHERE id = (SELECT user_id FROM list_user WHERE list_id = 0);
The subquery works (and I use it in code so the 0 is actually a variable) and it returns multiple rows. But the upper query only returns one row, which is pretty logical; I check if the id equals something and it only checks against the first row of the subquery.
How do I change my statement so I get multiple rows in the upper query?
I'm surprised the = works in SQLite. It would return an error in most databases. In any case, you want the in statement:
SELECT *
FROM list
WHERE id in (SELECT user_id FROM list_user WHERE list_id = 0);
For a better performance, use this query:
SELECT LIST.ID,
LIST.LIST_NAME,
LIST.LIST_DESCRIPTION
FROM LIST,
USER,
LIST_USER
WHERE LIST.ID = LIST_USER.USER_ID = USER.ID AND
LIST.LIST_ID = 0
I am using rawquery() for perform inner join, but this is not giving me any error and does not working, if i use this query directly into sqlite browser than this is working but in application this query does not work, following is my code, sorry for bad English communication
public void deleteFifo() {
final String MY_QUERY1 = "Delete from Items where res_id in (select _id from Favourite where _id not in (select _id from Favourite order by date desc limit 50))";
final String MY_QUERY2 = "Delete from Favourite where _id not in (select _id from Favourite order by date desc limit 50)";
db.rawQuery(MY_QUERY1, null);
db.rawQuery(MY_QUERY2, null);
}
Try:
db.delete(TableName, whereCondition, null);
i.e. in your case
db.delete("Items", "res_id in (select _id from Favourite where
_id not in (select _id from Favourite order by date desc limit 50))", null);
and
db.delete("Favourite ","_id not in (select _id from Favourite
order by date desc limit 50)");
Hope it helps !!
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.