我在哪里使用 CTE?需要替换为查询中的实际值:
val itemCursor: Cursor
val rdb = openHelper.writableDatabase
itemCursor = rdb.rawQuery(
menuItemsQuery(selection, sortOrder, projection),
selectionArgs
)
itemCursor.setNotificationUri(context.contentResolver, uri)
return itemCursor
其中 menuItemsQuery 有我的 SQL 查询,其中包含 CTE(公用表表达式)
WITH cteI AS ( SELECT " +
buildProjection(projection, "item.") +
",b." + InventoryContract.MenuItem.NAME + " AS " + Item.MENU_NAME +
" FROM " + Item.CONTENT_DIRECTORY + " INNER JOIN " +
InventoryContract.MenuItem.CONTENT_DIRECTORY + " AS b ON " +
Item.CONTENT_DIRECTORY + "." + Item.UUID + " = b." +
InventoryContract.MenuItem.ITEM_UUID + " WHERE ( " + selection + " ) )
上面的查询只是整个查询的CTE部分,其中selection包含?
我尝试更换?与@但没有运气
选择包含?
这很可能取决于选择还包含什么。
如果
?
被解释为绑定的占位符,则另一个依赖项将是 “运气不佳”。它不区分非预期结果和异常等。
当然,如果放置正确,
?
占位符可以在 CTE 中使用。下面演示了它的成功使用:-
示范
首先考虑以下内容(满足所有待确定的可变因素(您的问题使大多数问题未得到解决)):-
const val DATABASE_NAME = "the_database.db"
const val DATABASE_VERSION = 1
const val TABLE_A = "a"
const val COLUMN_A_ID = "${TABLE_A}_${BaseColumns._ID}"
const val COLUMN_A_C1 = "${TABLE_A}_c1"
const val COLUMN_A_C2 = "${TABLE_A}_c2"
const val TABLE_B = "b"
const val COLUMN_B_ID = "${TABLE_B}_${BaseColumns._ID}"
const val COLUMN_B_C1 = "${TABLE_B}_c1"
const val COLUMN_B_C2 = "${TABLE_B}_c2"
const val COLUMN_B_MAPTO_A_ID = "${TABLE_B}_mapto_$COLUMN_A_ID"
class OpenHelper: SQLiteOpenHelper {
override fun onCreate(db: SQLiteDatabase?) {
db!!.execSQL(
"CREATE TABLE IF NOT EXISTS $TABLE_A (" +
"${COLUMN_A_ID} INTEGER PRIMARY KEY" +
",${COLUMN_A_C1} TEXT " +
",${COLUMN_A_C2} TEXT " +
");"
)
db!!.execSQL(
"CREATE TABLE IF NOT EXISTS ${TABLE_B} (" +
"${COLUMN_B_ID} INTEGER PRIMARY KEY" +
",${COLUMN_B_C1} TEXT" +
",${COLUMN_B_C2} TEXT" +
",${COLUMN_B_MAPTO_A_ID} INTEGER" +
");"
)
}
override fun onUpgrade(db: SQLiteDatabase?, fromVersion: Int, toVersion: Int) {
}
constructor(context: Context) : super(context, DATABASE_NAME, null, DATABASE_VERSION) {
}
fun getItemCursor(stringToUseInWhereClause: String): Cursor {
val selection = "?"
val query = "WITH cte1 AS (SELECT " +
"* FROM ${TABLE_A} " +
"JOIN ${TABLE_B} ON ${TABLE_B}.${COLUMN_B_MAPTO_A_ID} = ${TABLE_A}.${COLUMN_A_ID} " +
"WHERE ${COLUMN_B_C1} LIKE " + selection +
"||'%'" +
")" +
"SELECT * FROM cte1;"
Log.d("DBINFO","GIC Query passed to SQLite is:-\n\t$query")
return this.writableDatabase.rawQuery(query, arrayOf(stringToUseInWhereClause))
}
fun getItemCursorOther(stringToUseInWhereClause: String): Cursor {
val query = "WITH cte1 AS (SELECT " +
"* FROM ${TABLE_A} " +
"JOIN ${TABLE_B} ON ${TABLE_B}.${COLUMN_B_MAPTO_A_ID} = ${TABLE_A}.${COLUMN_A_ID} " +
"WHERE ${COLUMN_B_C1} LIKE ?||'%'" +
")" +
"SELECT * FROM cte1;"
Log.d("DBINFO","GICO Query passed to SQLite is:-\n\t$query")
return this.writableDatabase.rawQuery(query, arrayOf(stringToUseInWhereClause))
}
fun insertA(id:Long?,c1: String, c2: String): Long {
val cv = ContentValues()
if (id != null) {
cv.put(COLUMN_A_ID,id)
}
cv.put(COLUMN_A_C1,c1)
cv.put(COLUMN_A_C2,c2)
return this.writableDatabase.insert(TABLE_A,null,cv)
}
fun insertB(id: Long?, c1: String, c2: String, mapToAId: Long): Long {
val cv = ContentValues()
if (id != null) {
cv.put(COLUMN_B_ID,id)
}
cv.put(COLUMN_B_C1,c1)
cv.put(COLUMN_B_C2,c2)
cv.put(COLUMN_B_MAPTO_A_ID,mapToAId)
return this.writableDatabase.insert(TABLE_B,null,cv)
}
}
getItemCursor
和等效的 getItemCursorOther
函数有 1 个细微差别;第一个使用变量 selection,其中包含占位符 (?
),而第二个则对占位符进行硬编码。
要绑定的实际术语/值(替换占位符)通过
stringToUseInWhereClause
传递给函数。
其余代码,只是让数据库实际使用并进行演示。
显然代码本身并不能证明什么。因此,为了实际演示占位符被替换为一些活动代码:-
活动代码:-
class MainActivity : AppCompatActivity() {
lateinit var openHelper: OpenHelper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
openHelper = OpenHelper(this)
val aid = openHelper.insertA(null,"c1blah","c2blah")
openHelper.insertB(100,"something","something",aid)
openHelper.insertB(null,"some thing but not really","something but not really",aid)
openHelper.insertB(null,"somethingelse","somethingelse",aid)
openHelper.insertB(null,"somethingelse","somethingelse",999)
val c1 = openHelper.getItemCursor("something")
DatabaseUtils.dumpCursor(c1)
val c2 = openHelper.getItemCursorOther("something")
DatabaseUtils.dumpCursor(c2)
val c3 = openHelper.getItemCursor("")
DatabaseUtils.dumpCursor(c3)
val c4 = openHelper.getItemCursorOther("")
DatabaseUtils.dumpCursor(c4)
c1.close()
c2.close()
c3.close()
c4.close()
}
}
日志的最终输出为:-
2024-01-17 09:45:29.080 D/DBINFO: GIC Query passed to SQLite is:-
WITH cte1 AS (SELECT * FROM a JOIN b ON b.b_mapto_a__id = a.a__id WHERE b_c1 LIKE ?||'%')SELECT * FROM cte1;
2024-01-17 09:45:29.080 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@8962cfb
2024-01-17 09:45:29.081 I/System.out: 0 {
2024-01-17 09:45:29.081 I/System.out: a__id=1
2024-01-17 09:45:29.082 I/System.out: a_c1=c1blah
2024-01-17 09:45:29.082 I/System.out: a_c2=c2blah
2024-01-17 09:45:29.082 I/System.out: b__id=100
2024-01-17 09:45:29.082 I/System.out: b_c1=something
2024-01-17 09:45:29.082 I/System.out: b_c2=something
2024-01-17 09:45:29.082 I/System.out: b_mapto_a__id=1
2024-01-17 09:45:29.082 I/System.out: }
2024-01-17 09:45:29.082 I/System.out: 1 {
2024-01-17 09:45:29.082 I/System.out: a__id=1
2024-01-17 09:45:29.082 I/System.out: a_c1=c1blah
2024-01-17 09:45:29.082 I/System.out: a_c2=c2blah
2024-01-17 09:45:29.082 I/System.out: b__id=102
2024-01-17 09:45:29.082 I/System.out: b_c1=somethingelse
2024-01-17 09:45:29.082 I/System.out: b_c2=somethingelse
2024-01-17 09:45:29.082 I/System.out: b_mapto_a__id=1
2024-01-17 09:45:29.082 I/System.out: }
2024-01-17 09:45:29.082 I/System.out: <<<<<
2024-01-17 09:45:29.082 D/DBINFO: GICO Query passed to SQLite is:-
WITH cte1 AS (SELECT * FROM a JOIN b ON b.b_mapto_a__id = a.a__id WHERE b_c1 LIKE ?||'%')SELECT * FROM cte1;
2024-01-17 09:45:29.083 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@ec7d118
2024-01-17 09:45:29.084 I/System.out: 0 {
2024-01-17 09:45:29.084 I/System.out: a__id=1
2024-01-17 09:45:29.084 I/System.out: a_c1=c1blah
2024-01-17 09:45:29.084 I/System.out: a_c2=c2blah
2024-01-17 09:45:29.084 I/System.out: b__id=100
2024-01-17 09:45:29.084 I/System.out: b_c1=something
2024-01-17 09:45:29.084 I/System.out: b_c2=something
2024-01-17 09:45:29.084 I/System.out: b_mapto_a__id=1
2024-01-17 09:45:29.084 I/System.out: }
2024-01-17 09:45:29.085 I/System.out: 1 {
2024-01-17 09:45:29.085 I/System.out: a__id=1
2024-01-17 09:45:29.085 I/System.out: a_c1=c1blah
2024-01-17 09:45:29.085 I/System.out: a_c2=c2blah
2024-01-17 09:45:29.086 I/System.out: b__id=102
2024-01-17 09:45:29.086 I/System.out: b_c1=somethingelse
2024-01-17 09:45:29.086 I/System.out: b_c2=somethingelse
2024-01-17 09:45:29.086 I/System.out: b_mapto_a__id=1
2024-01-17 09:45:29.086 I/System.out: }
2024-01-17 09:45:29.086 I/System.out: <<<<<
2024-01-17 09:45:29.086 D/DBINFO: GIC Query passed to SQLite is:-
WITH cte1 AS (SELECT * FROM a JOIN b ON b.b_mapto_a__id = a.a__id WHERE b_c1 LIKE ?||'%')SELECT * FROM cte1;
2024-01-17 09:45:29.086 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@d598771
2024-01-17 09:45:29.087 I/System.out: 0 {
2024-01-17 09:45:29.088 I/System.out: a__id=1
2024-01-17 09:45:29.088 I/System.out: a_c1=c1blah
2024-01-17 09:45:29.088 I/System.out: a_c2=c2blah
2024-01-17 09:45:29.088 I/System.out: b__id=100
2024-01-17 09:45:29.088 I/System.out: b_c1=something
2024-01-17 09:45:29.088 I/System.out: b_c2=something
2024-01-17 09:45:29.088 I/System.out: b_mapto_a__id=1
2024-01-17 09:45:29.088 I/System.out: }
2024-01-17 09:45:29.088 I/System.out: 1 {
2024-01-17 09:45:29.088 I/System.out: a__id=1
2024-01-17 09:45:29.088 I/System.out: a_c1=c1blah
2024-01-17 09:45:29.089 I/System.out: a_c2=c2blah
2024-01-17 09:45:29.089 I/System.out: b__id=101
2024-01-17 09:45:29.089 I/System.out: b_c1=some thing but not really
2024-01-17 09:45:29.091 I/System.out: b_c2=something but not really
2024-01-17 09:45:29.091 I/System.out: b_mapto_a__id=1
2024-01-17 09:45:29.091 I/System.out: }
2024-01-17 09:45:29.091 I/System.out: 2 {
2024-01-17 09:45:29.092 I/System.out: a__id=1
2024-01-17 09:45:29.092 I/System.out: a_c1=c1blah
2024-01-17 09:45:29.092 I/System.out: a_c2=c2blah
2024-01-17 09:45:29.092 I/System.out: b__id=102
2024-01-17 09:45:29.092 I/System.out: b_c1=somethingelse
2024-01-17 09:45:29.093 I/System.out: b_c2=somethingelse
2024-01-17 09:45:29.093 I/System.out: b_mapto_a__id=1
2024-01-17 09:45:29.093 I/System.out: }
2024-01-17 09:45:29.093 I/System.out: <<<<<
2024-01-17 09:45:29.093 D/DBINFO: GICO Query passed to SQLite is:-
WITH cte1 AS (SELECT * FROM a JOIN b ON b.b_mapto_a__id = a.a__id WHERE b_c1 LIKE ?||'%')SELECT * FROM cte1;
2024-01-17 09:45:29.094 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@8c94956
2024-01-17 09:45:29.095 I/System.out: 0 {
2024-01-17 09:45:29.095 I/System.out: a__id=1
2024-01-17 09:45:29.095 I/System.out: a_c1=c1blah
2024-01-17 09:45:29.095 I/System.out: a_c2=c2blah
2024-01-17 09:45:29.095 I/System.out: b__id=100
2024-01-17 09:45:29.096 I/System.out: b_c1=something
2024-01-17 09:45:29.096 I/System.out: b_c2=something
2024-01-17 09:45:29.096 I/System.out: b_mapto_a__id=1
2024-01-17 09:45:29.096 I/System.out: }
2024-01-17 09:45:29.096 I/System.out: 1 {
2024-01-17 09:45:29.096 I/System.out: a__id=1
2024-01-17 09:45:29.096 I/System.out: a_c1=c1blah
2024-01-17 09:45:29.096 I/System.out: a_c2=c2blah
2024-01-17 09:45:29.096 I/System.out: b__id=101
2024-01-17 09:45:29.096 I/System.out: b_c1=some thing but not really
2024-01-17 09:45:29.096 I/System.out: b_c2=something but not really
2024-01-17 09:45:29.096 I/System.out: b_mapto_a__id=1
2024-01-17 09:45:29.096 I/System.out: }
2024-01-17 09:45:29.096 I/System.out: 2 {
2024-01-17 09:45:29.097 I/System.out: a__id=1
2024-01-17 09:45:29.097 I/System.out: a_c1=c1blah
2024-01-17 09:45:29.097 I/System.out: a_c2=c2blah
2024-01-17 09:45:29.097 I/System.out: b__id=102
2024-01-17 09:45:29.097 I/System.out: b_c1=somethingelse
2024-01-17 09:45:29.097 I/System.out: b_c2=somethingelse
2024-01-17 09:45:29.097 I/System.out: b_mapto_a__id=1
2024-01-17 09:45:29.097 I/System.out: }
2024-01-17 09:45:29.097 I/System.out: <<<<<
因此
?
占位符必须替换为selectionArgs参数中的值,因此您遇到的问题不是由于?无法用选择参数中的值替换,而是在其他地方(由于问题的模糊性实际上无法确定)。但是,演示确实包含一些调试代码,在尝试确定实际问题时可能会有用。