I'm trying to get the the ten latest entries in my sqlite database. I need to fetch only one entry at a time instead of those ten entries at once.
Until now, i was doing this:
"SELECT " + sql + " FROM " + TABLE_NAME
+ " WHERE _id = (SELECT max(_id)-2 FROM " + TABLE_NAME + ")";
For every entry i need, i was just doing ...max(_id)-x but this does not work, if some entries are deleted at some time. The id's have some gaps (like 1, 2, 4, 8, ...).
So after some research i was trying something like this:
"SELECT * FROM (SELECT " + sql + ", rank() over (order by max(_id) desc) rk
FROM " + TABLE_NAME + " GROUP BY " + sql + ") t WHERE rk = 2"
this approach however crashes with the following message
android.database.sqlite.SQLiteException: near "(": syntax error (code 1): , while compiling: select * from (select price, rank() over (order by max(_id) desc) rk from refuels group by price) t where rk = 2
How can I get this done? Thanks in advance
I found a simple and easy solution:
"SELECT " + sql + " FROM " + TABLE_NAME + " ORDER BY _id DESC LIMIT 1 offset n"
where the n is the number of the entry -1. Meaning, I want row number 6, n has to be 5.
Related
I am working on Spark SQL and I am trying to get the records using following queries:
/*Select all open tasks which are not unscheduled*/
Dataset<Row> scheduledOpenTasks = sqlContext.sql(
"SELECT * "
+ "FROM OpenTaskTable "
+ "WHERE due_date < cast('" + unscheduledDate + "' as timestamp)");
scheduledOpenTasks.createOrReplaceTempView("ScheduledOpenTaskTable");
/*Select scheduled tasks with max due_date for each csg_order_id*/
Dataset<Row> scheduledTasks = sqlContext.sql(
"SELECT TS1.* from ScheduledOpenTaskTable AS TS1 "
+ "INNER JOIN "
+ " (SELECT csg_order_id, MAX(due_date) AS MaxDD"
+ " FROM ScheduledOpenTaskTable"
+ " GROUP BY csg_order_id) AS TS2 "
+ "ON TS1.csg_order_id = TS2.csg_order_id AND TS1.due_date = TS2.MaxDD");
The unscheduled _date has value 4444-12-30.
In the OpenTaskTable, each csg_order_id can have multiple due_dates including unscheduled_date. I need the csg_order_ids with corresponding highest due_dates except unscheduled_date.
Now, with first query, I am removing all the records which have due_date as unscheduled_date. In second query, I am retrieving all the records with max due_date for each csg_order_id.
Now comes the problem: is there any way to combine these queries as one?
Well, after struggling for a while, finally found a way to combine the above two queries like this:
sqlContext.sql("SELECT OT1.* from OpenTaskTable AS OT1 INNER JOIN "
+ "(SELECT OT2.csg_order_id, MAX(OT2.due_date) AS MaxDD FROM "
+ "(SELECT csg_order_id, due_date from OpenTaskTable WHERE due_date < cast('"+unscheduledDate+"' as timestamp)) AS OT2 "
+ "GROUP BY OT2.csg_order_id) AS OT3 "
+ "ON OT1.csg_order_id = OT3.csg_order_id AND OT1.due_date = OT3.MaxDD");
Explanation:
Previously, in the first query, I was retrieving data from OpenTaskTable and then feeding it to the second query. Logically, in the second query also, I am just applying more filters over the retrieved data. At the end, we are trying to get all the attributes from OpenTaskTable only.
So, for this solution I simply used the first query, as the innermost query, and then selected MAX over the records grouped by csg_order_id. And, for the outermost query, just performed an inner join to get all matching csg_order_id records from OpenTaskTable.
"MERGE INTO NT_PROPERTY ntProp USING ( " +
"SELECT * FROM NT_PROPERTY ) " +
"VALUES " +
"('minDPTObjectId'," + minDPTObjectId + ", 'Starting DPT Object Id') " +
"('maxDPTObjectId', " + maxDPTObjectId + ", 'Ending DPT Object Id') " +
"vt (NAME, VALUE, NOTE) " +
"ON ( ntProp.NAME = vt.NAME ) " +
"WHEN MATCHED THEN " +
"UPDATE SET VALUE = vt.VALUE "+
"WHEN NOT MATCHED THEN " +
"INSERT (NAME, VALUE, NOTE) VALUES (vt.NAME, vt.VALUE, vt.NOTE)";
Well I'm getting a missing ON keyword error and with no clue what so ever, also is there any other way to make it less clumsy
Help is very much appreciated.
The problem is that your MERGE syntax is incorrect. Your statement takes the form of:
MERGE INTO nt_property ntprop
USING (SELECT * FROM nt_property)
VALUES (...)
vt (...)
ON (ntprop.name = vt.name)
WHEN MATCHED THEN
UPDATE ...
WHEN NOT MATCHED THEN
INSERT ...;
but it should be of the form:
MERGE INTO target_table tgt_alias
USING source_table_or_subquery src_alias
ON (<JOIN conditions>)
WHEN MATCHED THEN
UPDATE ...
WHEN NOT MATCHED THEN
INSERT ...;
Why do you have the VALUES and vt clauses between your using and your on clauses? That's the incorrect syntax. Also, whilst you can use select * from tablename in the using clause, you could just use the tablename directly, since you're selecting all columns and all rows.
MERGE INTO NT_PROPERTY D
USING (SELECT * FROM DUAL ) S
ON (D.NAME = 'minDPTObjectId')
WHEN MATCHED THEN UPDATE SET D.VALUE = '1234'
WHEN NOT MATCHED THEN INSERT (NAME, VALUE, NOTE)
VALUES ('maxDPTObjectId', '1111', 'Ending DPT Object Id') ;
I'm having an issue with a SQL query in Android - it doesn't seem to be returning the correct result, which I think might be due to my query structure possibly.
This is a running app. I have an initial query that works correctly, that gets me the most common out of the last three runs, which is:
Cursor workout = db.rawQuery("SELECT ActivityID, DistanceID FROM Workout WHERE _id IN(Select _id FROM Workout ORDER BY _id DESC LIMIT 3) Group By ActivityID, DistanceID HAVING COUNT(*) > 1", null);
So now I have the most common distance + activity (running/biking ect..) out of the last three runs, so I wanted to run a query that got me the activity + distance combination on the last three with the fasted time, so I have this:
Cursor fastestWorkout = db.rawQuery
("Select _id, RunTimeSeconds, Distance FROM Workout WHERE ActivityID = " + workout.getInt(0) +
" AND DistanceID = " + workout.getInt(1) +
" AND RunTimeSeconds IN " +
"(Select Min(RunTimeSeconds) From Workout WHERE ActivityID = " + workout.getInt(0) +
" AND DistanceID = " + workout.getInt(1) +
" ORDER BY _id DESC LIMIT 3)" +
" ORDER BY _id DESC LIMIT 3", null);
So the only thing special here is the sub-query that gets me the fastest time, which I imagine might be at fault, however I can't work out why. The cursor has three results in it at the end of this, when it should be one (There are two activities+distances that are the same and one unique - with different RunTimeSeconds, so it should be pulling back that one that is the fastest.
Any help would be appreciated!
If I understand correctly you want the row with the fastest run time. Instead of using a subquery to find this value, why not just order by this run time and pick the first result :
Cursor fastestWorkout = db.rawQuery
("Select _id, RunTimeSeconds, Distance FROM Workout WHERE ActivityID = " + workout.getInt(0) +
" AND DistanceID = " + workout.getInt(1) +
" ORDER BY RunTimeSeconds LIMIT 1", null);
Thanks for the help! I managed to figure this one out in the end! Bwt's suggestion with the ordering by run-time is what got me there!
I just used a sub-query to select from the last three runs, then I could order by the run-time and limit it to just one result, getting the fastest run!
Cursor fastestWorkout = db.rawQuery
("Select _id, RunTimeSeconds, DistanceID FROM (Select _id, RunTimeSeconds, DistanceID, ActivityID FROM Workout ORDER BY _id DESC LIMIT 3) WHERE ActivityID = " + workout.getInt(0) +
" AND DistanceID = " + workout.getInt(1) +
" ORDER BY RunTimeSeconds LIMIT 1", null);
Thanks for your help ans answers!
Good day. I have a query in my Java code that deletes duplicate rows in a table. Initially it worked and for a while i didn't touch the project. But on running the file a few days ago, my code was throwing exceptions. This is my code:
String query = "DELETE error_log FROM error_log INNER JOIN "
+ "(SELECT min(id) minid, service_source, channel,transaction_type, provider_name, pido_account, beneficiary_id, error_description, error_date FROM error_log "
+ "GROUP BY service_source, channel, transaction_type, provider_name, pido_account, beneficiary_id, error_description, error_date "
+ "HAVING COUNT(1) > 1 AS duplicates ON "
+ "(duplicates.service_source = error_log.service_source AND duplicates.channel = error_log.channel "
+ "AND duplicates.transaction_type = error_log.transaction_type AND duplicates.provider_name = error_log.provider_name "
+ "AND duplicates.pido_account = error_log.pido_account AND duplicates.beneficiary_id = error_log.beneficiary_id "
+ "AND duplicates.error_description = error_log.error_description AND duplicates.error_date = error_log.error_date "
+ "AND duplicates.minid <> error_log.id"
+ ")"
+ ")";
int deploy = duplicate.executeUpdate(query);
I get this afterwards:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AS duplicates ON (duplicates.service_source = error_log.service_source AND dupli' at line 1.
How do i correct this and have the duplicates deleted from the table?
You have a missing ) on line + "HAVING COUNT(1) > 1 AS duplicates ON " and have an extra ) at the end.
String query = "DELETE error_log FROM error_log INNER JOIN "
+ "(SELECT min(id) minid, service_source, channel,transaction_type, provider_name, pido_account, beneficiary_id, error_description, error_date FROM error_log "
+ "GROUP BY service_source, channel, transaction_type, provider_name, pido_account, beneficiary_id, error_description, error_date "
+ "HAVING COUNT(1) > 1 ) AS duplicates ON "
+ "(duplicates.service_source = error_log.service_source AND duplicates.channel = error_log.channel "
+ "AND duplicates.transaction_type = error_log.transaction_type AND duplicates.provider_name = error_log.provider_name "
+ "AND duplicates.pido_account = error_log.pido_account AND duplicates.beneficiary_id = error_log.beneficiary_id "
+ "AND duplicates.error_description = error_log.error_description AND duplicates.error_date = error_log.error_date "
+ "AND duplicates.minid <> error_log.id"
+ ")";
int deploy = duplicate.executeUpdate(query);
If you haven't made any changes and it stopped working, 1) are you sure you tested this code? and 2) has anyone else made any changes without your knowledge?
Problem Synopsis:
When attempting to execute a SQL query in Java with a SQLite Database, the SQL statement fails to return from the execute() or executeQuery() method. In other words, the system "hangs" when executing this SQL statement.
Question:
What am I doing wrong to explain why the ResultSet never "returns?"
TroubleShooting
I tried to narrow the problem and the problem seems to be with the Java execute() or executeQuery(). A ResultSet never seems to return. For example, I tried executing exactly the same query directly in SQLite (that is, using a SQLite DB manager). The query (outside Java) executes in about 5ms and returns the valid result set.
NOTE: No exception is thrown. The system merely seems to "hang" and becomes unresponsive until a manual kill. (waiting more than 10 minutes.)
Code:
I heavily edited this code to make the problem simpler to see. (In production, this uses Prepared Statements. But, the error occurs in both methods--straight Statement and prepared Statement versions.)
Basically, the SELECT returns a single DB item so the user can review that item.
Statement st = conn.createStatement() ;
ResultSet rs = st.executeQuery("SELECT DISTINCT d1.id, d1.sourcefullfilepath, " +
"d1.sourcefilepath, d1.sourcefilename, d1.classificationid, d1.classid, " +
"d1.userid FROM MatterDataset, (SELECT MatterDataset.id, " +
"MatterDataset.sourcefullfilepath, MatterDataset.sourcefilepath, " +
"MatterDataset.sourcefilename, MatterDataset.matterid , " +
"DocumentClassification.classificationid, DocumentClassification.classid," +
" DocumentClassification.userid FROM MatterDataset " +
"LEFT JOIN DocumentClassification ON " +
"DocumentClassification.documentid = Matterdataset.id " +
"WHERE ( DocumentClassification.classid = 1 OR " +
"DocumentClassification.classid = 2 ) AND " +
"DocumentClassification.userid < 0 AND " +
"MatterDataset.matterid = \'100\' ) AS d1 " +
"LEFT JOIN PrivilegeLog ON " +
"d1.id = PrivilegeLog.documentparentid AND " +
"d1.matterid = PrivilegeLog.matterid " +
"WHERE PrivilegeLog.privilegelogitemid IS NULL " +
"AND MatterDataset.matterid = \'100\' " +
"ORDER BY d1.id LIMIT 1 ;") ;
Configuration:
Java 6,
JDBC Driver = Xerial sqlite-jdbc-3.7.2,
SQLite 3,
Windows
Update
Minor revision: as I continue to work with this, adding a MIN(d1.id) to the beginning of the SQL statement at least returns a ResultSet (rather than "hanging"). But, this is not really what I wanted as the MIN obviates the LIMIT function.
Statement st = conn.createStatement() ;
ResultSet rs = st.executeQuery("SELECT DISTINCT MIN(d1.id), d1.id,
d1.sourcefullfilepath, " +
"d1.sourcefilepath, d1.sourcefilename, d1.classificationid, d1.classid, " +
"d1.userid FROM MatterDataset, (SELECT MatterDataset.id, " +
"MatterDataset.sourcefullfilepath, MatterDataset.sourcefilepath, " +
"MatterDataset.sourcefilename, MatterDataset.matterid , " +
"DocumentClassification.classificationid, DocumentClassification.classid," +
" DocumentClassification.userid FROM MatterDataset " +
"LEFT JOIN DocumentClassification ON " +
"DocumentClassification.documentid = Matterdataset.id " +
"WHERE ( DocumentClassification.classid = 1 OR " +
"DocumentClassification.classid = 2 ) AND " +
"DocumentClassification.userid < 0 AND " +
"MatterDataset.matterid = \'100\' ) AS d1 " +
"LEFT JOIN PrivilegeLog ON " +
"d1.id = PrivilegeLog.documentparentid AND " +
"d1.matterid = PrivilegeLog.matterid " +
"WHERE PrivilegeLog.privilegelogitemid IS NULL " +
"AND MatterDataset.matterid = \'100\' " +
"ORDER BY d1.id LIMIT 1 ;") ;
What a messy SQL statement (sorry)! I don't know SQLite, but why not simplify to:
SELECT DISTINCT md.id, md.sourcefullfilepath, md.sourcefilepath, md.sourcefilename,
dc.classificationid, dc.classid, dc.userid
FROM MatterDataset md
LEFT JOIN DocumentClassification dc
ON dc.documentid = md.id
AND (dc.classid = 1 OR dc.classid = 2 )
AND dc.userid < 0
LEFT JOIN PrivilegeLog pl
ON md.id = pl.documentparentid
AND md.matterid = pl.matterid
WHERE pl.privilegelogitemid IS NULL
AND md.matterid = \'100\'
ORDER BY md.id LIMIT 1 ;
I was uncertain whether you wanted to LEFT JOIN or INNER JOIN to DocumentClassification (using LEFT JOIN and then put requirements on classid and userid in the WHERE statement is - in my opinion - contradictory). If DocumentClassification has to exist, then change to INNER JOIN and put the references to classid and userid into the WHERE clause, if DocumentClassification may or may not exist in your result set, then keep the query as I suggested above.
I went back and started over. The SQL syntax, while it worked outside Java, simply seemed too complex for the JDBC driver. This cleaned-up revision seems to work:
SELECT DISTINCT
MatterDataset.id, MatterDataset.sourcefullfilepath, MatterDataset.sourcefilepath,
MatterDataset.sourcefilename
FROM MatterDataset , DocumentClassification
ON DocumentClassification.documentid = MatterDataset.id
AND MatterDataset.matterid = DocumentClassification.matterid
LEFT JOIN PrivilegeLog ON MatterDataset.id = PrivilegeLog.documentparentid
AND MatterDataset.matterid = PrivilegeLog.matterid
WHERE PrivilegeLog.privilegelogitemid IS NULL
AND MatterDataset.matterid = '100'
AND (DocumentClassification.classid = 1 OR DocumentClassification.classid = 2)
AND DocumentClassification.userid = -99
ORDER BY MatterDataset.id LIMIT 1;
A nice lesson in: just because you can in SQL doesn't mean you should.
What this statement does is essentially locates items in the MatterDataset Table that are NOT in the PrivilegeLog table. The LEFT JOIN and IS NULL syntax locate the items that are "missing." That is, i want to find items that are in MatterDataset but not yet in PrivilegeLog and return those items.