在 Android 的 SQLite 中使用 INNER JOIN 时遇到问题
Trouble using INNER JOIN in SQLite in Android
我在本地服务器上有一个 MySQL 数据库。我通过 HTTP 使用 PHP 和 JSON 从 MySQL 数据库中获取数据。在 Android 应用程序中,使用 JSON 结果填充 SQLite 数据库。我已经验证 SQLite 数据库实际上是由 运行ning 类似于
的测试查询填充的
Cursor cursor = database.rawQuery("SELECT recipe_id, ingredient_id, name FROM mm_ingredient_in_recipe_groups", null);
然后迭代生成的游标以查看数据是否存在。存在的数据存储在三个 table 中:
mm_ingredients
,包含食谱的成分。
mm_recipes
,包含配方数据。
mm_ingredient_in_recipe
,包含用于连接 mm_recipes
和 mm_ingredients
中数据的数据(即解决多对多关系)。
我想要做的是 运行 一个为参数配方名称选择成分的查询。这意味着我必须使用 mm_ingredient_in_recipe
和 mm_recipes
.
INNER JOIN mm_ingredients
我已经尝试 运行以下查询:
database.rawQuery("SELECT ingredient.name, ingredient.base_unit FROM mm_ingredients AS ingredient INNER JOIN mm_ingredient_in_recipe AS ir ON ir.ingredient_id = ingredient._id INNER JOIN mm_recipes AS recipe ON ir.recipe_id = recipe._id WHERE recipe.name = ?", new String[] {"Spicy tomatsuppe"});
此 returns 一个空游标。然而,在我的 MySQL 数据库中,运行 宁相应的查询
SELECT ingredient.name, ingredient.base_unit FROM mm_ingredients AS ingredient INNER JOIN mm_ingredient_in_recipe AS ir ON ir.ingredient_id = ingredient.id INNER JOIN mm_recipes AS recipe ON ir.recipe_id = recipe.id WHERE recipe.name = "Spicy tomatsuppe";
returns 预期的数据。我在这里做错了什么?似乎我 运行 的每个查询在我开始包含 INNER JOIN 之前都运行良好。 (id 字段在 SQLite 中被命名为 _id,据我所知这应该是最佳实践。)
编辑:添加写入数据库的代码:
下面是我如何为 table mm_recipes
填充数据库的示例。其他两个 table 也是类似的。我对 SQLite 的 TEXT
数据类型使用 JSONArray.optString()
,对 INTEGER
使用 JSONArray.optInt()
,对 REAL
.
使用 JSONArray.optDouble()
public static final String TABLE_NAME = "mm_recipes";
public static final String TABLE_NAME_IN_JSON = "mm_recipes";
public static final String COLUMN_ID = "_id";
public static final String COLUMN_NAME = "name";
public static final String COLUMN_IN_APP = "in_app";
public static final String COLUMN_DIFFICULTY = "difficulty";
public static final String COLUMN_TIME_CONSUMPTION_UPPER = "time_consumption_upper";
public static final String COLUMN_TIME_CONSUMPTION_LOWER = "time_consumption_lower";
public static final String COLUMN_PREPARATION_TIME = "preparation_time";
public static final String COLUMN_PORTIONS = "portions";
public static final String COLUMN_PORTIONS_UNIT = "portions_unit";
public static final String COLUMN_DESCRIPTION = "description";
public static final String COLUMN_TIPS = "tips";
public static final String COLUMN_USE_INGREDIENT_GROUPS = "use_ingredient_groups";
public static final void populateDatabase(SQLiteDatabase database, JSONObject databaseData) throws JSONException{
JSONArray table_data = databaseData.optJSONArray(TABLE_NAME_IN_JSON);
ContentValues contentValues = new ContentValues();
for (int i = 0; i < table_data.length(); i++){
JSONObject data = table_data.getJSONObject(i);
contentValues.clear();
contentValues.put(COLUMN_NAME, data.optString(COLUMN_NAME));
contentValues.put(COLUMN_IN_APP, data.optInt(COLUMN_IN_APP));
contentValues.put(COLUMN_DIFFICULTY, data.optString(COLUMN_DIFFICULTY));
contentValues.put(COLUMN_TIME_CONSUMPTION_UPPER, data.optInt(COLUMN_TIME_CONSUMPTION_UPPER));
contentValues.put(COLUMN_TIME_CONSUMPTION_LOWER, data.optInt(COLUMN_TIME_CONSUMPTION_LOWER));
contentValues.put(COLUMN_PREPARATION_TIME, data.optInt(COLUMN_PREPARATION_TIME));
contentValues.put(COLUMN_PORTIONS, data.optInt(COLUMN_PORTIONS));
contentValues.put(COLUMN_PORTIONS_UNIT, data.optString(COLUMN_PORTIONS_UNIT));
contentValues.put(COLUMN_DESCRIPTION, data.optString(COLUMN_DESCRIPTION));
contentValues.put(COLUMN_TIPS, data.optString(COLUMN_TIPS));
contentValues.put(COLUMN_USE_INGREDIENT_GROUPS, data.optInt(COLUMN_USE_INGREDIENT_GROUPS));
database.insert(TABLE_NAME, null, contentValues);
}
}
作为参考,这里还有一个如何创建 mm_recipe
table 的示例。在我的 class 中 mm_recipe
:
public static final String DATATYPE_ID = "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL";
public static final String DATATYPE_NAME = "TEXT NOT NULL";
public static final String DATATYPE_IN_APP = "INTEGER DEFAULT 0";
public static final String DATATYPE_DIFFICULTY = "TEXT NOT NULL";
public static final String DATATYPE_TIME_CONSUMPTION_UPPER = "INTEGER NOT NULL";
public static final String DATATYPE_TIME_CONSUMPTION_LOWER = "INTEGER NOT NULL";
public static final String DATATYPE_PREPARATION_TIME = "INTEGER";
public static final String DATATYPE_PORTIONS = "INTEGER NOT NULL";
public static final String DATATYPE_PORTIONS_UNIT = "TEXT NOT NULL";
public static final String DATATYPE_DESCRIPTION = "TEXT";
public static final String DATATYPE_TIPS = "TEXT";
public static final String DATATYPE_USE_INGREDIENT_GROUPS = "INT";
/**Create table statement.*/
public static final String CREATE_TABLE =
"CREATE TABLE" + " " + TABLE_NAME + " (" +
COLUMN_ID + " " + DATATYPE_ID + ", " +
COLUMN_NAME + " " + DATATYPE_NAME + ", " +
COLUMN_IN_APP + " " + DATATYPE_IN_APP + ", " +
COLUMN_DIFFICULTY + " " + DATATYPE_DIFFICULTY + ", " +
COLUMN_TIME_CONSUMPTION_UPPER + " " + DATATYPE_TIME_CONSUMPTION_UPPER + ", " +
COLUMN_TIME_CONSUMPTION_LOWER + " " + DATATYPE_TIME_CONSUMPTION_LOWER + ", " +
COLUMN_PREPARATION_TIME + " " + DATATYPE_PREPARATION_TIME + ", " +
COLUMN_PORTIONS + " " + DATATYPE_PORTIONS + ", " +
COLUMN_PORTIONS_UNIT + " " + DATATYPE_PORTIONS_UNIT + ", " +
COLUMN_DESCRIPTION + " " + DATATYPE_DESCRIPTION + ", " +
COLUMN_TIPS + " " + DATATYPE_TIPS + ", " +
COLUMN_USE_INGREDIENT_GROUPS + " " + DATATYPE_USE_INGREDIENT_GROUPS + ");";
在我的 SQLiteOpenHelper
class:
@Override
public void onCreate(SQLiteDatabase database) {
database.execSQL(Table_mm_recipes.CREATE_TABLE);
database.execSQL(Table_mm_ingredient_in_recipe.CREATE_TABLE);
database.execSQL(Table_mm_ingredients.CREATE_TABLE);
}
事实证明这是(如预期的那样)一些愚蠢的错误。我就把它留在这里,以防其他人犯类似的错误。
由于我已经设置了每次创建时删除数据库中所有内容的代码,因此:
database.execSQL("DELETE FROM " + Table_mm_recipes.TABLE_NAME);
database.execSQL("DELETE FROM " + Table_mm_ingredient_in_recipe.TABLE_NAME);
database.execSQL("DELETE FROM " + Table_mm_ingredients.TABLE_NAME);
数据不知何故发生了一些不好的事情。这样做并没有多大意义,因为您只需创建数据库并在 SQLiteOpenHelper.onCreate()
处插入数据就可以了。如果您需要在设置任何版本控制之前更新数据,只需卸载并重新安装该应用程序。然后,如果愿意,您可以销毁 SQLiteOpenHelper.onUpgrade()
处的数据。我不确定 如何 数据被弄乱了,但肯定是这样。
奇怪的是,通过执行一个简单的
,我仍然可以看到数据库中有数据
Cursor cursor = database.rawQuery("SELECT recipe_id, ingredient_id, name FROM mm_ingredient_in_recipe_groups", null);
并迭代之前的光标。我在 INNER JOIN
语句之前直接对所有表执行了此操作,但它们仍然不起作用。应该和数据库的错误deletion/creation有关。
除此之外,上面的所有代码都应该有效。
我在本地服务器上有一个 MySQL 数据库。我通过 HTTP 使用 PHP 和 JSON 从 MySQL 数据库中获取数据。在 Android 应用程序中,使用 JSON 结果填充 SQLite 数据库。我已经验证 SQLite 数据库实际上是由 运行ning 类似于
的测试查询填充的Cursor cursor = database.rawQuery("SELECT recipe_id, ingredient_id, name FROM mm_ingredient_in_recipe_groups", null);
然后迭代生成的游标以查看数据是否存在。存在的数据存储在三个 table 中:
mm_ingredients
,包含食谱的成分。mm_recipes
,包含配方数据。mm_ingredient_in_recipe
,包含用于连接mm_recipes
和mm_ingredients
中数据的数据(即解决多对多关系)。
我想要做的是 运行 一个为参数配方名称选择成分的查询。这意味着我必须使用 mm_ingredient_in_recipe
和 mm_recipes
.
mm_ingredients
我已经尝试 运行以下查询:
database.rawQuery("SELECT ingredient.name, ingredient.base_unit FROM mm_ingredients AS ingredient INNER JOIN mm_ingredient_in_recipe AS ir ON ir.ingredient_id = ingredient._id INNER JOIN mm_recipes AS recipe ON ir.recipe_id = recipe._id WHERE recipe.name = ?", new String[] {"Spicy tomatsuppe"});
此 returns 一个空游标。然而,在我的 MySQL 数据库中,运行 宁相应的查询
SELECT ingredient.name, ingredient.base_unit FROM mm_ingredients AS ingredient INNER JOIN mm_ingredient_in_recipe AS ir ON ir.ingredient_id = ingredient.id INNER JOIN mm_recipes AS recipe ON ir.recipe_id = recipe.id WHERE recipe.name = "Spicy tomatsuppe";
returns 预期的数据。我在这里做错了什么?似乎我 运行 的每个查询在我开始包含 INNER JOIN 之前都运行良好。 (id 字段在 SQLite 中被命名为 _id,据我所知这应该是最佳实践。)
编辑:添加写入数据库的代码:
下面是我如何为 table mm_recipes
填充数据库的示例。其他两个 table 也是类似的。我对 SQLite 的 TEXT
数据类型使用 JSONArray.optString()
,对 INTEGER
使用 JSONArray.optInt()
,对 REAL
.
JSONArray.optDouble()
public static final String TABLE_NAME = "mm_recipes";
public static final String TABLE_NAME_IN_JSON = "mm_recipes";
public static final String COLUMN_ID = "_id";
public static final String COLUMN_NAME = "name";
public static final String COLUMN_IN_APP = "in_app";
public static final String COLUMN_DIFFICULTY = "difficulty";
public static final String COLUMN_TIME_CONSUMPTION_UPPER = "time_consumption_upper";
public static final String COLUMN_TIME_CONSUMPTION_LOWER = "time_consumption_lower";
public static final String COLUMN_PREPARATION_TIME = "preparation_time";
public static final String COLUMN_PORTIONS = "portions";
public static final String COLUMN_PORTIONS_UNIT = "portions_unit";
public static final String COLUMN_DESCRIPTION = "description";
public static final String COLUMN_TIPS = "tips";
public static final String COLUMN_USE_INGREDIENT_GROUPS = "use_ingredient_groups";
public static final void populateDatabase(SQLiteDatabase database, JSONObject databaseData) throws JSONException{
JSONArray table_data = databaseData.optJSONArray(TABLE_NAME_IN_JSON);
ContentValues contentValues = new ContentValues();
for (int i = 0; i < table_data.length(); i++){
JSONObject data = table_data.getJSONObject(i);
contentValues.clear();
contentValues.put(COLUMN_NAME, data.optString(COLUMN_NAME));
contentValues.put(COLUMN_IN_APP, data.optInt(COLUMN_IN_APP));
contentValues.put(COLUMN_DIFFICULTY, data.optString(COLUMN_DIFFICULTY));
contentValues.put(COLUMN_TIME_CONSUMPTION_UPPER, data.optInt(COLUMN_TIME_CONSUMPTION_UPPER));
contentValues.put(COLUMN_TIME_CONSUMPTION_LOWER, data.optInt(COLUMN_TIME_CONSUMPTION_LOWER));
contentValues.put(COLUMN_PREPARATION_TIME, data.optInt(COLUMN_PREPARATION_TIME));
contentValues.put(COLUMN_PORTIONS, data.optInt(COLUMN_PORTIONS));
contentValues.put(COLUMN_PORTIONS_UNIT, data.optString(COLUMN_PORTIONS_UNIT));
contentValues.put(COLUMN_DESCRIPTION, data.optString(COLUMN_DESCRIPTION));
contentValues.put(COLUMN_TIPS, data.optString(COLUMN_TIPS));
contentValues.put(COLUMN_USE_INGREDIENT_GROUPS, data.optInt(COLUMN_USE_INGREDIENT_GROUPS));
database.insert(TABLE_NAME, null, contentValues);
}
}
作为参考,这里还有一个如何创建 mm_recipe
table 的示例。在我的 class 中 mm_recipe
:
public static final String DATATYPE_ID = "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL";
public static final String DATATYPE_NAME = "TEXT NOT NULL";
public static final String DATATYPE_IN_APP = "INTEGER DEFAULT 0";
public static final String DATATYPE_DIFFICULTY = "TEXT NOT NULL";
public static final String DATATYPE_TIME_CONSUMPTION_UPPER = "INTEGER NOT NULL";
public static final String DATATYPE_TIME_CONSUMPTION_LOWER = "INTEGER NOT NULL";
public static final String DATATYPE_PREPARATION_TIME = "INTEGER";
public static final String DATATYPE_PORTIONS = "INTEGER NOT NULL";
public static final String DATATYPE_PORTIONS_UNIT = "TEXT NOT NULL";
public static final String DATATYPE_DESCRIPTION = "TEXT";
public static final String DATATYPE_TIPS = "TEXT";
public static final String DATATYPE_USE_INGREDIENT_GROUPS = "INT";
/**Create table statement.*/
public static final String CREATE_TABLE =
"CREATE TABLE" + " " + TABLE_NAME + " (" +
COLUMN_ID + " " + DATATYPE_ID + ", " +
COLUMN_NAME + " " + DATATYPE_NAME + ", " +
COLUMN_IN_APP + " " + DATATYPE_IN_APP + ", " +
COLUMN_DIFFICULTY + " " + DATATYPE_DIFFICULTY + ", " +
COLUMN_TIME_CONSUMPTION_UPPER + " " + DATATYPE_TIME_CONSUMPTION_UPPER + ", " +
COLUMN_TIME_CONSUMPTION_LOWER + " " + DATATYPE_TIME_CONSUMPTION_LOWER + ", " +
COLUMN_PREPARATION_TIME + " " + DATATYPE_PREPARATION_TIME + ", " +
COLUMN_PORTIONS + " " + DATATYPE_PORTIONS + ", " +
COLUMN_PORTIONS_UNIT + " " + DATATYPE_PORTIONS_UNIT + ", " +
COLUMN_DESCRIPTION + " " + DATATYPE_DESCRIPTION + ", " +
COLUMN_TIPS + " " + DATATYPE_TIPS + ", " +
COLUMN_USE_INGREDIENT_GROUPS + " " + DATATYPE_USE_INGREDIENT_GROUPS + ");";
在我的 SQLiteOpenHelper
class:
@Override
public void onCreate(SQLiteDatabase database) {
database.execSQL(Table_mm_recipes.CREATE_TABLE);
database.execSQL(Table_mm_ingredient_in_recipe.CREATE_TABLE);
database.execSQL(Table_mm_ingredients.CREATE_TABLE);
}
事实证明这是(如预期的那样)一些愚蠢的错误。我就把它留在这里,以防其他人犯类似的错误。
由于我已经设置了每次创建时删除数据库中所有内容的代码,因此:
database.execSQL("DELETE FROM " + Table_mm_recipes.TABLE_NAME);
database.execSQL("DELETE FROM " + Table_mm_ingredient_in_recipe.TABLE_NAME);
database.execSQL("DELETE FROM " + Table_mm_ingredients.TABLE_NAME);
数据不知何故发生了一些不好的事情。这样做并没有多大意义,因为您只需创建数据库并在 SQLiteOpenHelper.onCreate()
处插入数据就可以了。如果您需要在设置任何版本控制之前更新数据,只需卸载并重新安装该应用程序。然后,如果愿意,您可以销毁 SQLiteOpenHelper.onUpgrade()
处的数据。我不确定 如何 数据被弄乱了,但肯定是这样。
奇怪的是,通过执行一个简单的
,我仍然可以看到数据库中有数据Cursor cursor = database.rawQuery("SELECT recipe_id, ingredient_id, name FROM mm_ingredient_in_recipe_groups", null);
并迭代之前的光标。我在 INNER JOIN
语句之前直接对所有表执行了此操作,但它们仍然不起作用。应该和数据库的错误deletion/creation有关。
除此之外,上面的所有代码都应该有效。