SQLite, Kotlin, Android. Запрос SELECT с переменным числом аргументов - PullRequest
0 голосов
/ 24 мая 2019

Я создаю приложение для Android с Kotlin. Использует SQlite

Мне нужно выбрать данные из таблицы, а условие запроса зависит от аргументов метода

это как

fun getData(a:String, b:String, c:String): Array<String> {
    val db = readableDatabase
    var selectALLQuery = "SELECT * FROM $TABLE "
    var conditions:ArrayList<String> = arrayListOf()
    var arguments: // WHAT should be type?

    if (a != "") {
         // add a to the query with WHERE
         conditions.add("a = ?")
         // add a value to arguments. how?
    }
    if (b != "") {
         // add b to the query with WHERE
         conditions.add("b = ?")
         // add b value to arguments. how?
    }
    if (c != "") {
         // add c to the query with WHERE
         conditions.add("c = ?")
         // add b value to arguments. how?
    }
    if (conditions.count() > 0) {
         selectALLQuery += " WHERE "+conditions.joinToString(" AND ")
    }
    val cursor = db.rawQuery(selectALLQuery, arguments)
}

Это хороший подход? Есть лучшие способы? Если это основной способ, какой тип аргументов должен быть переменным?

Обновление

Я нашел решение, чтобы пропустить использование шаблонов SQL и просто создать запрос полностью самостоятельно, а поля TEXT заключаются в кавычки с DatabaseUtils.sqlEscapeString.

Ответы [ 3 ]

1 голос
/ 25 мая 2019

Может быть, это будет полезно:

fun buildQuery(mainQuery: String, vararg args: Pair<String, Any>): String {
    return mainQuery + if (args.isNotEmpty()) {
         args.map {
            "${it.first} = ${it.second}"
        }.joinToString(" AND ")
    } else {
        ""
    }
}

Тогда вызов:

val query = buildQuery("SELECT * FROM PERSON ", "a" to "Tim", "b" to 77)
println(query)

Вывод:

SELECT * FROM PERSON a = Tim AND b = 77
1 голос
/ 25 мая 2019

аргументы var: // ЧТО должно быть типа?

Метод rawQuery ожидает массив.

Я бы использовал

fun getDataV2(a: String, b: String, c: String): ArrayList<String> {

    val rv = ArrayList<String>()            //Return value
    var sql = "SELECT * FROM $TABLE "       //Core SQL ro always be used
    val values = arrayOf(a, b, c)           //Convert inputs to an array
    val columns = arrayOf("a", "b", "c")    //Likewise for the columns
    val arguments = ArrayList<String>()     //Initially 0 arguments
    val whereclause = StringBuilder()       //Initially empty whereclause
    var after_first = false                 //Flag to indicate whether the first arg has been added
    for (i in values.indices) {             //Loop through values
        if (values[i].length > 0) {         //Is there a value?
            if (after_first) {              //Is this not the first value
                whereclause.append(" AND ") //If it is not the first value add the ADD keyword
            }
            whereclause.append(columns[i]).append("=?") //if there is a value then add the expression
            arguments.add(values[i])        // and then add the value to the arguments ArrayList
            after_first = true              // change flag to indicate that a value has been processed
        }
    }
    // Add the WHERE keyword and the where clause if needed
    if (whereclause.isNotEmpty()) {
        sql = "$sql WHERE $whereclause"
    }

    //Prepare to run the rawQuery
    val db = this.writableDatabase
    //Run the rawQuery
    val csr = db.rawQuery(sql, arguments.toTypedArray())
    Log.d("GETDATAV2",sql + " Argcount =" + arguments.size) //TODO for testing, REMOVE before publising
    //Populate the ArrayList to be returned from the Cursor
    while (csr.moveToNext()) {
        rv.add(csr.getString(csr.getColumnIndex(COLNAME))) //<<<<<<<<<< COLNAME assumed for testing
    }
    //CLose the Cursor
    csr.close()
    //Finally return the ArrayList
    return rv
}

Тестирование

Использование следующего в упражнении для проверки ряда премий: -

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val dbHelper = DBHelperKotlin(this)
    dbHelper.writableDatabase.delete(DBHelper.TABLE,null,null); //Delete any existing rows
    // Add the testing data
    dbHelper.add("Test1", "a", "b", "c")
    dbHelper.add("Test2", "b", "c", "d")
    dbHelper.add("Test3", "c", "d", "e")
    dbHelper.add("Test4", "d", "e", "f")

    //testing against older method removed (hence starting with 3) 
    val result3 = dbHelper.getDataV2("","","");
    for (i in result3.indices) {
        Log.d("TEST1V2RESULT",result3.get(i))
    }

    val result4 = dbHelper.getDataV2("","b","");
    for (i in result4.indices) {
        Log.d("TEST4V2RESULT",result4.get(i))
    }

    val result5 = dbHelper.getDataV2("a","b","c");
    for (i in result5.indices) {
        Log.d("TEST5V2RESULT",result5.get(i))
    }

    val result6 = dbHelper.getDataV2("a","","");
    for (i in result6.indices) {
        Log.d("TEST6V2RESULT",result6.get(i))
    }

    val result7 = dbHelper.getDataV2("","","c");
    for (i in result7.indices) {
        Log.d("TEST7V2RESULT",result7.get(i))
    }

    val result8 = dbHelper.getDataV2("a","","c");
    for (i in result8.indices) {
        Log.d("TEST8V2RESULT",result8.get(i))
    }
}

Результаты в

05-26 12:23:36.452 3593-3593/? D/GETDATAV2: SELECT * FROM mytable  Argcount =0
05-26 12:23:36.452 3593-3593/? D/TEST1V2RESULT: Test1
05-26 12:23:36.452 3593-3593/? D/TEST1V2RESULT: Test2
05-26 12:23:36.452 3593-3593/? D/TEST1V2RESULT: Test3
05-26 12:23:36.452 3593-3593/? D/TEST1V2RESULT: Test4
05-26 12:23:36.452 3593-3593/? D/GETDATAV2: SELECT * FROM mytable  WHERE b=? Argcount =1
05-26 12:23:36.453 3593-3593/? D/TEST4V2RESULT: Test1
05-26 12:23:36.453 3593-3593/? D/GETDATAV2: SELECT * FROM mytable  WHERE a=? AND b=? AND c=? Argcount =3
05-26 12:23:36.454 3593-3593/? D/TEST5V2RESULT: Test1
05-26 12:23:36.455 3593-3593/? D/GETDATAV2: SELECT * FROM mytable  WHERE a=? Argcount =1
05-26 12:23:36.455 3593-3593/? D/TEST6V2RESULT: Test1
05-26 12:23:36.455 3593-3593/? D/GETDATAV2: SELECT * FROM mytable  WHERE c=? Argcount =1
05-26 12:23:36.456 3593-3593/? D/TEST7V2RESULT: Test1
05-26 12:23:36.456 3593-3593/? D/GETDATAV2: SELECT * FROM mytable  WHERE a=? AND c=? Argcount =2
05-26 12:23:36.458 3593-3593/? D/TEST8V2RESULT: Test1

Однако

С простой модификацией вышеупомянутое может быть намного более гибким и обслуживать любое количество столбцов в любой таблице (при условии, что столбцы существуют в указанной таблице) согласно: -

fun getDataV3(table: String, args: Array<String>, columns: Array<String>) : ArrayList<String> {

    val rv = ArrayList<String>()            //Return value
    var sql = "SELECT * FROM $table "       //Core SQL ro always be used

    if (args.size != columns.size) {
        // handle mismatch between columns and args??????
        return rv
    }

    val arguments = ArrayList<String>()     //Initially 0 arguments
    val whereclause = StringBuilder()       //Initially empty whereclause
    var after_first = false                 //Flag to indicate whether the first arg has been added
    for (i in args.indices) {             //Loop through values
        if (args[i].length > 0) {         //Is there a value?
            if (after_first) {              //Is this not the first value
                whereclause.append(" AND ") //If it is not the first value add the ADD keyword
            }
            whereclause.append(columns[i]).append("=?") //if there is a value then add the expression
            arguments.add(args[i])        // and then add the value to the arguments ArrayList
            after_first = true              // change flag to indicate that a value has been processed
        }
    }
    // Add the WHERE keyword and the where clause if needed
    if (whereclause.isNotEmpty()) {
        sql = "$sql WHERE $whereclause"
    }

    //Prepare to run the rawQuery
    val db = this.writableDatabase
    //Run the rawQuery
    val csr = db.rawQuery(sql, arguments.toTypedArray())
    Log.d("GETDATAV3",sql + " Argcount =" + arguments.size) //TODO for testing, REMOVE before publising
    //Populate the ArrayList to be returned from the Cursor
    while (csr.moveToNext()) {
        rv.add(csr.getString(csr.getColumnIndex(COLNAME)))
    }
    //CLose the Cursor
    csr.close()
    //Finally return the ArrayList
    return rv
}

И затем может быть вызван как: -

    val result10 = dbHelper.getDataV3(DBHelperKotlin.TABLE,arrayOf("","",""), arrayOf(DBHelperKotlin.COLA,DBHelperKotlin.COLB,DBHelperKotlin.COLC))
    for (i in result10.indices) {
        Log.d("TEST10V2RESULT",result10.get(i))
    }
    val result11 = dbHelper.getDataV3(DBHelperKotlin.TABLE,arrayOf("","b",""), arrayOf(DBHelperKotlin.COLA,DBHelperKotlin.COLB,DBHelperKotlin.COLC))
    for (i in result11.indices) {
        Log.d("TEST11V2RESULT",result11.get(i))
    }

В результате вышесказанного: -

05-26 12:52:24.444 3960-3960/aso.so56298529querywithmultileargs D/GETDATAV3: SELECT * FROM mytable  Argcount =0
05-26 12:52:24.444 3960-3960/aso.so56298529querywithmultileargs D/TEST10V2RESULT: Test1
05-26 12:52:24.444 3960-3960/aso.so56298529querywithmultileargs D/TEST10V2RESULT: Test2
05-26 12:52:24.444 3960-3960/aso.so56298529querywithmultileargs D/TEST10V2RESULT: Test3
05-26 12:52:24.444 3960-3960/aso.so56298529querywithmultileargs D/TEST10V2RESULT: Test4
05-26 12:52:24.444 3960-3960/aso.so56298529querywithmultileargs D/GETDATAV3: SELECT * FROM mytable  WHERE b=? Argcount =1
05-26 12:52:24.444 3960-3960/aso.so56298529querywithmultileargs D/TEST11V2RESULT: Test1
0 голосов
/ 25 мая 2019

a, b, c - все String с.

Таким образом, вы можете ввести arguments в виде списка String.

val arguments = mutableListOf<String>()

Причина, по которой я использовал MutableList вместо Array, заключается в динамическом добавлении элементов.

Внутри ваших if операторов, после добавления условия, вы можете добавить элемент в arguments, например,

arguments.add(a)

Наконец, в db.rawQuery() вы можете передать это как массив, используя toTypedArray.

db.rawQuery(selectALLQuery, arguments.toTypedArray())

Анко

В Kotlin вы можете упростить подключение к базе данных и запросы, используя Anko .

https://github.com/Kotlin/anko/wiki/Anko-SQLite

Проверка Запрос данных часть.

...