sqlLiteDatabase.query() 用于内部连接

sqlLiteDatabase.query() for INNER JOIN

我想从 Android SQLite 数据库中执行如下查询:

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

我正在尝试使用 query(),而不是 rawQuery()。 我不知道如何指定 INNER JOIN/ON。 我该怎么做?

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

您将无法将查询与联接一起使用,而是将 rawquery 与联接一起使用

    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);

您有 2 个选择:

  1. 使用rawQuery方法
  2. 从 SELECT 语句创建视图并在其上使用 query 方法

编辑:

SQLite 支持视图 - 您可以查看文档 here。 通常你可以 运行 这样的声明:

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

您应该 运行 SQLite Helper class 的 onCreate 方法中的此语句 - 即您定义数据库的方法 tables。之后,您可以使用 "my_view",就好像它是具有 2 列("name" 和 "distance")的 table。

不过我不建议使用这种方法 - 它可能会使您的数据库变得有点混乱,而且我不确定它对性能有何影响!

编辑 2:

搞砸 rawQuery 和视图语句 - 似乎是更好的解决方案。

您可以将联接放在 table 变量中。

String table = "tblLocal local " +
    "inner join tblPlaces place " +
    "on place._id = local._id";

有关示例,请参阅 Google 的 IOSched 应用程序。看看 provider package and the SelectionBuilder class.

A SQLiteQueryBuilder 用于构造查询字符串,它所做的只是将 table 变量连接到查询的其余部分。参见 https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/database/sqlite/SQLiteQueryBuilder.java#201

我只是想添加一个示例,其中包含来自实际应用程序的代码,但我的解决方案与@rubenlop88 基本相同,即在 table 变量中进行连接。我和您一样,不想使用 rawquery,因为我希望能够使用 SQLiteQueryBuilder 在内容提供程序中包含选择和投影参数。我记得当时获取编写此代码所需的信息对我来说非常困难,所以我 post 希望它能帮助其他人。

在我的 app/database 中,我有两个 table。一个包含信号列表。另一个包含事件列表,其中每个事件(即打开或关闭)对应于特定信号。我的 tables 之一是一个简单的连接,它将所有事件与其特定信号合并。另一个 table 是一个更复杂的连接示例,它允许我查询所有信号的当前状态。

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;
}

以下是在查询中使用 JOIN 的两种方法

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);