问题
I want to do a query as follows from an Android SQLite db:
select place.permit_name, local.local_distance
from tblLocal local
inner join tblPlaces place
on place._id = local._id
order by local.local_distance asc
I'm trying to use query()
, instead of rawQuery()
.
I don't know how to specify the INNER JOIN/ON.
How do I do this?
final String table = PlacesDataContract.PlacesDataEntry.TABLE_NAME;
final String[] columns = { PlacesDataContract.PlacesDataEntry.COLUMN_NAME_PERMIT_NAME. , LocalDataContract.LocalDataEntry.COLUMN_NAME_LOCAL_DISTANCE};
final String orderBy = LocalDataContract.LocalDataEntry.COLUMN_NAME_LOCAL_DISTANCE + " ASC";
Cursor cursor = sqLiteDatabase.query(table, // table
columns, // columns
null, // selection
null, // selectionArgs
null, // groupBy
null, // having
orderBy, // orderBy
null); // limit
回答1:
You can put the join in the table
variable.
String table = "tblLocal local " +
"inner join tblPlaces place " +
"on place._id = local._id";
See the IOSched app from Google for an example. Take a look at the provider package and the SelectionBuilder class.
A SQLiteQueryBuilder
is used to construct the query string, and all it does is concatenate the table variable to the rest of the query. See https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/database/sqlite/SQLiteQueryBuilder.java#201
回答2:
You have 2 options:
- Use
rawQuery
method - Create a view from the SELECT statement and use the
query
method on it
EDIT:
SQLite supports views - you could take a look at the docs here. Generally you could run a statement like this:
CREATE VIEW my_view AS
SELECT place.permit_name as name, local.local_distance as distance
FROM tblLocal local
INNER JOIN tblPlaces place
ON place._id = local._id
ORDER BY local.local_distance ASC
You should run this statement in the onCreate method of the SQLite Helper class - i.e. the method where you define you database tables. After that you could work with "my_view" as if it is a table with 2 columns ("name" and "distance").
I wouldn't recommend using this approach though - it could make your database a little messier and I'm not sure how it impacts the performance!
EDIT 2:
Screw both rawQuery and view statements - this seems to be a better solution.
回答3:
You wont be able to use query with your joins, instead use rawquery with joins
String sql = "select place.permit_name, local.local_distance\n" +
"from tblLocal local\n" +
"inner join tblPlaces place\n" +
"on place._id = local._id\n" +
"order by local.local_distance asc";
Cursor cursor = sqLiteDatabase.rawQuery(sql, null);
回答4:
I just wanted to add an example with code from an actual app, but my solution is essentially the same as @rubenlop88, which is to do the join in a table variable. I, like you, didn't want to use a rawquery
because I wanted to be able to include selection and projection parameters in a content provider using the SQLiteQueryBuilder
. I remember getting the information I needed to write this code was pretty hard for me at the time so I post it in hopes that it will help someone else.
In my app/database, I have two tables. One contains a list of signals. The other contains a list of events where each event(ie, switch on or switch off) corresponds with a certain signal. One of my tables is a simple join that merges all the events with their particular signal. The other table is a more complex example of join that allows me to query the current state of all the signals.
private static final String TABLE_JOINED_EVENTS_SIGNALS = DataContract.LinEventEntry.TABLE_NAME + " INNER JOIN " +
DataContract.LinSignalTable.TABLE_NAME + " ON " +
DataContract.LinSignalTable._ID + "=" + DataContract.LinEventEntry.COLUMN_NAME_SIGNAL_ID;
/**
* Using this constant as a parameter for
* {@link android.database.sqlite.SQLiteQueryBuilder#setTables(String)} will create a query
* that gets the highest id (most recent) row for each unique signal name
*/
private static final String TABLE_MAX_ID_GROUP_BY_SIGNAL =
"(SELECT max(" + DataContract.LinEventEntry._ID + ") as max_id " +
"FROM " + DataContract.LinEventEntry.TABLE_NAME +
" GROUP BY " + DataContract.LinEventEntry.COLUMN_NAME_SIGNAL_ID + ") " +
"as t1 INNER JOIN " + DataContract.LinEventEntry.TABLE_NAME +
" as t2 on t1.max_id=t2." + DataContract.LinEventEntry._ID +
" INNER JOIN " + DataContract.LinSignalTable.TABLE_NAME + " ON " +
DataContract.LinSignalTable._ID + "=" + DataContract.LinEventEntry.COLUMN_NAME_SIGNAL_ID;
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
if (sortOrder == null || sortOrder.isEmpty()) {
sortOrder = DEFAULT_EVENT_SORT_ORDER;
}
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables(TABLE_JOINED_EVENTS_SIGNALS);
switch (sURIMatcher.match(uri)) {
case EVENTS:
break;
case SIGNAL_NAME:
queryBuilder.appendWhere(DataContract.COLUMN_NAME_SIGNAL_NAME +
"='" + uri.getLastPathSegment() + "'");
break;
case EVENT_ID:
queryBuilder.appendWhere(
DataContract.LinEventEntry._ID + "=" + uri.getLastPathSegment());
break;
case EVENTS_BY_SIGNAL:
queryBuilder.setTables(TABLE_MAX_ID_GROUP_BY_SIGNAL);
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
SQLiteDatabase db = mSqlHelper.getReadableDatabase();
Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null,
sortOrder, MAX_EVENTS_TO_RETURN);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
回答5:
Following are two Ways of using JOIN
in your query
TABLE1
,TABLE2
are table names andTABLE1.THREAD_ID
,TABLE2.KEY_TREAD_ID
are column names
1.Using .rawQuery()
String rawQuery = "SELECT * FROM " +TABLE1 + " INNER JOIN " + TABLE2
+ " ON " + TABLE1 .THREAD_ID + " = " + TABLE2.KEY_TREAD_ID;
return db.rawQuery(rawQuery,null);
2.Using .query()
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.enableWriteAheadLogging();
String tableName =TABLE1 + " INNER JOIN " + TABLE2 + " ON " + TABLE1+ "." +TABLE1.THREAD_ID + " = " + TABLE2+ "." +TABLE2.KEY_TREAD_ID;
Projection and .query()
String[] projectio = new String[]{
TABLE1 + "." + TABLE1.KEY_PARENT,
TABLE2 + "." + TABLE2 .KEY_STUDENT}
return queryBuilder.query(db, projectio, null, null, null,
null, null);
来源:https://stackoverflow.com/questions/31567564/sqllitedatabase-query-for-inner-join