SQLite ORDER BY result of nested query - android

I have a table with multiple date fields, and I would like to select the rows with the dates closest to the current date, regardless of which column it is.
There are 2 tables in the database;
Covers:
create table covers (_id integer primary key autoincrement, "
+ "stallionName integer not null, mareName integer not null, firstCoverDate text not null, lastCoverDate text not null, "
+ "scan14Date text not null, scan28Date text not null, foalingDate text not null, inFoal integer not null, notes text not null," +
"FOREIGN KEY (stallionName) REFERENCES horses (_id), FOREIGN KEY (mareName) REFERENCES horses (_id))
stallionName and mareName are integers that reference the row _id of the relevant horse in the horse table (As such, the SQL query has multiple joins to get the names for the stallion and mare, instead of just the row _id). All date columns are of the form 'YYYY-MM-DD'
and horses:
create table horses (_id integer primary key autoincrement, "
+ "name text not null, type integer not null, birthDate text not null, vaccineDate text not null, "
+ "inFoal integer not null, notes text not null)
type is an integer referencing a spinner position (type is either mare, stallion, gelding etc)
I want to select 5 rows from the covers table with values of scan14Date, scan28Date and foalingDate that are nearest to today's date (i.e. the 5 most urgent rows)
This is my effort so far;
SELECT covers.* horses1.name AS stallionNameText, horses2.name AS mareNameText
FROM horses horses1 JOIN covers ON horses1._id = covers.stallionName JOIN horses horses2 ON horses2._id = covers.MareName
WHERE covers._id IN
(SELECT DISTINCT _id FROM
(SELECT covers.scan14Date AS date, covers._id
FROM covers
WHERE date > dateToday
UNION
SELECT covers.scan28Date AS date, covers._id
FROM covers
WHERE date > dateToday
UNION
SELECT covers.foalingDate AS date, covers._id
FROM covers
WHERE date > dateToday
ORDER BY date)
LIMIT 5)
(It can be assumed that 'dateToday' is also of the form YYYY-MM-DD. It's sorted out in java)
Now, the nested query below successfully selects the 5 'most urgent' row _ids;
(SELECT DISTINCT _id FROM
(SELECT covers.scan14Date AS date, covers._id
FROM covers
WHERE date > dateToday
UNION
SELECT covers.scan28Date AS date, covers._id
FROM covers
WHERE date > dateToday
UNION
SELECT covers.foalingDate AS date, covers._id
FROM covers
WHERE date > dateToday
ORDER BY date)
LIMIT 5)
And the first section successfully gets all the data for the row _id selected above;
SELECT covers.* horses1.name AS stallionNameText, horses2.name AS mareNameText
FROM horses horses1 JOIN covers ON horses1._id = covers.stallionName JOIN horses horses2 ON horses2._id = covers.MareName
WHERE covers._id IN
....
The issue I'm having is that the order of the row _ids returned by the nested query is lost in the overall query. If for example the nested query returns the row _ids (6, 3, 4, 12, 15) the overall query displays it in the order (3, 4, 6, 12, 15)
I would then like to return the stallion name, mare name, lastCoverDate, 14ScanDate, 28ScanDate and foalingDate.
My question is how can I maintain the order returned by the inner query? I naively tried to add ORDER BY date at the very end, but it predictably says there is no such column.
Thankyou for taking the time to read.
(Also, I'm sure that my SQL query won't be the most efficient way of doing it, but I'm fairly new to all this)

Include the date in the result of the inner query, then you can order by date in the outer query. Your Java wrapper can simply ignore the date field in the result.

Related

Get all rows from group by query

I have database sqlite contain 2 tables:
names
n_data
and query:
select
n_data.id,n_data.value, count( n_data.id) as count
from
n_data
INNER JOIN names on names.id = n_data.name_id
group by
n_data.name_id
order by
n_data.id asc
In activity I have used
Cursor and while
while (res.moveToNext()) {
System.out.println("id=>"+res.getString(0)+" count=>"+res.getString(2)+" =value=>"+res.getString(1));
}
but result just show last row in group. How can I get all rows for every group?
CREATE TABLE "names" (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT );
INSERT INTO names (id,name) VALUES
(1,'name_1'),
(2,'name_2'),
(3,'name_3'),
(4,'name_4');
CREATE TABLE "n_data" (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name_id TEXT,
value TEXT );
INSERT INTO n_data (id,name_id,value) VALUES
(1,'3','value_8'),
(2,'2','value_7'),
(3,'2','value_6'),
(4,'2','value_5'),
(5,'1','value_4'),
(6,'1','value_3'),
(7,'1','value_2'),
(8,'1','value_1'),
(9,'3','value_9');
OP is satisfied by:
select
n_data.id,
group_concat(n_data.value) as 'all values',
count( n_data.id) as count
from
n_data INNER JOIN names
on names.id = n_data.name_id
group by n_data.name_id
order by n_data.id asc;
It uses group_concat(n_data.value) instead of n_data.value.
I.e. all the data.value which get counted by count(n_data.id) are concatenated.
Output (.headers on, .mode column and .width 3 32 6; SQLite 3.18.0 2017-03-28) :
id all values count
--- -------------------------------- ------
4 value_7,value_6,value_5 3
8 value_4,value_3,value_2,value_1 4
9 value_8,value_9 2
The tailored .width is needed, otherwise for id 8, only 3 values are shown, though 4 are retrieved.

SqlLiteDatabase.query order by date column not working

I'm developing an Android app based on SqlLiteDataBase.
When I query the db using the query method, I want to order by a date column in ascending order.
It seems the ORDERBY is not working.
Cursor cursor = db.query("myTable", // The table to query
dbTools.tableColumns, // The columns to return
whereClause, // The columns for the WHERE clause
null, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
"dateText" + " ASC" // The sort order
);
The cursor mquery field during debug shows the following:
SQLiteQuery: SELECT dateText, <some other columns here> FROM myTable WHERE dateText >= '2015-10-01 00:00:00' AND dateText <= '2015-10-31 23:59:59' ORDER BY dateText DESC
(I removed irrelevant columns for your convenience)
After running the query, I want to check whether I have any entry, so I call:
if (!cursor.moveToFirst())
Then I do some logic and whenever I want to move to next row on cursor I run:
if (!cursor.moveToNext())
dateText column is defined as DATETIME:
String query = "CREATE TABLE myTable (id INTEGER PRIMARY KEY AUTOINCREMENT, dateText DATETIME, <other columns here>)";
Can you please advise why the sorting is not working? The rows are not sorted when iterating over the rows on the cursor.
Example:
if I have rows for 1st, 2nd and 10th of November 2015, the sorting by ASC will give this sorting: 10->1->2
Sorting by DESC gives: 2->10->1
here what i propose to you to try :
SQLiteQuery: SELECT dateText, FROM myTable WHERE dateText >= '2015-10-01 00:00:00' AND dateText <= '2015-10-31 23:59:59' ORDER BY date(dateText) DESC
and Be-careful for :
Dest ==> Descendant
ASC ==> Ascendant
Good luck !!
I want to order by a date column in ascending order
But your code show
ORDER BY dateText DESC
Change it ASC is default option, so you can remove it
ORDER BY dateText ASC

SQlite query for stop times in GTFS data

I am working with GTFS data on Android (SQlite). And I would like to improve performance when I do select queries in my database filled with GTFS data.
The query below select the stop times associated to a route at a stop:
The first sub query gets the daily stop times on thursday.
The second gets all the exception stop times which are not valid for TODAY (2013-07-25).
The third one gets all the exception stop time which are only valid for TODAY (2013-07-25).
Then I remove the non-valid one and add the valid one to the first sub query.
select distinct stop_times_arrival_time
from stop_times, trips, calendar
where stop_times_trip_id=trip_id
and calendar_service_id=trip_service_id
and trip_route_id='11821949021891616'
and stop_times_stop_id='3377699721872252'
and calendar_start_date<='20130725'
and calendar_end_date>='20130725'
and calendar_thursday=1
and stop_times_arrival_time>='07:40'
except
select stop_times_arrival_time
from stop_times, trips, calendar, calendar_dates
where stop_times_trip_id=trip_id
and calendar_service_id=trip_service_id
and calendar_dates_service_id = trip_service_id
and trip_route_id='11821949021891694'
and stop_times_stop_id='3377699720880977'
and calendar_thursday=1
and calendar_dates_exception_type=2
and stop_times_arrival_time > '07:40'
and calendar_dates_date = 20130725
union
select stop_times_arrival_time
from stop_times, trips, calendar, calendar_dates
where stop_times_trip_id=trip_id
and calendar_service_id=trip_service_id
and calendar_dates_service_id = trip_service_id
and trip_route_id='11821949021891694'
and stop_times_stop_id='3377699720880977'
and calendar_thursday=1
and calendar_dates_exception_type=1
and stop_times_arrival_time > '07:40'
and calendar_dates_date = 20130725;
It took about 15 seconds to compute (which is very long).
I am sure there is a better to do this query since I do 3 different queries (almost the same by the way) which take time.
Any idea how to improve it?
EDIT:
Here is the schema:
table|calendar|calendar|2|CREATE TABLE calendar (
calendar_service_id TEXT PRIMARY KEY,
calendar_monday INTEGER,
calendar_tuesday INTEGER,
calendar_wednesday INTEGER,
calendar_thursday INTEGER,
calendar_friday INTEGER,
calendar_saturday INTEGER,
calendar_sunday INTEGER,
calendar_start_date TEXT,
calendar_end_date TEXT
)
index|sqlite_autoindex_calendar_1|calendar|3|
table|calendar_dates|calendar_dates|4|CREATE TABLE calendar_dates (
calendar_dates_service_id TEXT,
calendar_dates_date TEXT,
calendar_dates_exception_type INTEGER
)
table|routes|routes|8|CREATE TABLE routes (
route_id TEXT PRIMARY KEY,
route_short_name TEXT,
route_long_name TEXT,
route_type INTEGER,
route_color TEXT
)
index|sqlite_autoindex_routes_1|routes|9|
table|stop_times|stop_times|12|CREATE TABLE stop_times (
stop_times_trip_id TEXT,
stop_times_stop_id TEXT,
stop_times_stop_sequence INTEGER,
stop_times_arrival_time TEXT,
stop_times_pickup_type INTEGER
)
table|stops|stops|13|CREATE TABLE stops (
stop_id TEXT PRIMARY KEY,
stop_name TEXT,
stop_lat REAL,
stop_lon REAL
)
index|sqlite_autoindex_stops_1|stops|14|
table|trips|trips|15|CREATE TABLE trips (
trip_id TEXT PRIMARY KEY,
trip_service_id TEXT,
trip_route_id TEXT,
trip_headsign TEXT,
trip_direction_id INTEGER,
trip_shape_id TEXT
)
index|sqlite_autoindex_trips_1|trips|16|
And here is the query plan:
2|0|0|SCAN TABLE stop_times (~33333 rows)
2|1|1|SEARCH TABLE trips USING INDEX sqlite_autoindex_trips_1 (trip_id=?) (~1 rows)
2|2|2|SEARCH TABLE calendar USING INDEX sqlite_autoindex_calendar_1 (calendar_service_id=?) (~1 rows)
3|0|3|SCAN TABLE calendar_dates (~10000 rows)
3|1|2|SEARCH TABLE calendar USING INDEX sqlite_autoindex_calendar_1 (calendar_service_id=?) (~1 rows)
3|2|0|SEARCH TABLE stop_times USING AUTOMATIC COVERING INDEX (stop_times_stop_id=?) (~7 rows)
3|3|1|SEARCH TABLE trips USING INDEX sqlite_autoindex_trips_1 (trip_id=?) (~1 rows)
1|0|0|COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (EXCEPT)
4|0|3|SCAN TABLE calendar_dates (~10000 rows)
4|1|2|SEARCH TABLE calendar USING INDEX sqlite_autoindex_calendar_1 (calendar_service_id=?) (~1 rows)
4|2|0|SEARCH TABLE stop_times USING AUTOMATIC COVERING INDEX (stop_times_stop_id=?) (~7 rows)
4|3|1|SEARCH TABLE trips USING INDEX sqlite_autoindex_trips_1 (trip_id=?) (~1 rows)
0|0|0|COMPOUND SUBQUERIES 1 AND 4 USING TEMP B-TREE (UNION)
Columns that are used for lookups should be indexed, but for a single (sub)query, it is not possible to use more than one index per table.
For this particular query, the following additional indexes would help:
CREATE INDEX some_index ON stop_times(
stop_times_stop_id,
stop_times_arrival_time);
CREATE INDEX some_other_index ON calendar_dates(
calendar_dates_service_id,
calendar_dates_exception_type,
calendar_dates_date);

group and sort sqlite records

I have a table with the following cols
_id INTEGER PRIMARY KEY,
body TEXT,
category TEXT,
is_readed INTEGER,
date INTEGER
i have the records look the example
i have the following query
SELECT
_id, body, category, is_readed
FROM
table
GROUP BY
category
ORDER BY
category, is_readed, date DESC
i want show only the first record for category (regardless of whether is_readed is 0 or 1) but i want show first (if exist) the record with is_readed == 1. but sometimes show first record with is_readed == 0 even if exist one with is_readed == 1
Note: I'm using ContentProvider not raw queries
Update
after try a while with this roughly work
SELECT
_id, body, category, MIN(is_readed) as is_readed
FROM
table
GROUP BY
category
ORDER BY
category, date DESC
i still are making tests but I'm still not convinced
Examples
SELECT * FROM table ORDER BY category, is_readed ASC, date DESC;
_id|category|body|is_readed|date
19|Hogar|message1|1|1371449889136
16|Hogar|message2|1|1371449806704
15|Hogar|message2|1|1371449803825
11|Hogar|message3|1|1371448915930
5|Hogar|message4|1|1371447395055
4|Hogar|message4|1|1371447391394
23|Linea blanca|message2|0|1371450430216
26|Linea blanca|message1|1|1371450719124
24|Linea blanca|message4|1|1371450431604
21|Linea blanca|message1|1|1371449893835
20|Linea blanca|message1|1|1371449891488
17|Linea blanca|message3|1|1371449810104
13|Linea blanca|message3|1|1371448994173
12|Linea blanca|message2|1|1371448917864
6|Linea blanca|message4|1|1371447397387
22|Vehiculos|message3|0|1371450428817
14|Vehiculos|message3|0|1371449801144
25|Vehiculos|message4|1|1371450717115
18|Vehiculos|message4|1|1371449887682
10|Vehiculos|message1|1|1371448422563
9|Vehiculos|message4|1|1371448419438
8|Vehiculos|message3|1|1371448416315
7|Vehiculos|message4|1|1371448395644
3|Vehiculos|message3|1|1371447388887
2|Vehiculos|message1|1|1371447386126
1|Vehiculos|message2|1|1371447383557
My Update
SELECT
_id, body, category, MIN(is_readed) as is_readed
FROM
table
GROUP BY
category
ORDER BY
category, date DESC
_id|category|body|is_readed|date
4|Hogar|message4|1|1371447391394
23|Linea blanca|message2|0|1371450430216
14|Vehiculos|message3|0|1371449801144
#Hoan Nguyen answer
4|Hogar|message4|1|1371447391394
6|Linea blanca|message4|1|1371447397387
1|Vehiculos|message2|1|1371447383557
Expected result
19|Hogar|message1|1|1371449889136
23|Linea blanca|message2|0|1371450430216
22|Vehiculos|message3|0|1371450428817
I had to implement raw queries in my ContentProvider and also a subquery, but I think that can be performed without the subquery
SELECT
_id, body, category, is_readed, date
FROM
(
SELECT
_id, body, category, is_readed, date
FROM
table
GROUP BY
is_readed, category
ORDER BY
category ASC, is_readed DESC, date DESC
)
GROUP BY
category
SELECT
_id, body, category, is_readed
FROM
table
GROUP BY
category
HAVING
max (is_readed)
ORDER BY
category, is_readed, date DESC

SQLite subquery

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

Categories

Resources