sqlLiteDatabase.query() for INNER JOIN

蹲街弑〆低调 提交于 2019-12-24 06:38:27

问题


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:

  1. Use rawQuery method
  2. 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 and TABLE1.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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!