How to combine 2 or more Sqflite queries with logical operators? - flutter

Im currently trying to combine the results of 2 queries in flutter. These are the queries:
Future<List> filterExercises({
List<String> equipmentFilter,
List<String> muscleFilter,
int custom, //0 = false, 1 = true
int recent, //0 = false, 1 = true
String orderBy,
}) async {
Database db = await initDatabase();
final muscleRes = await db.query(
'exercises',
where: "targetMuscle IN (${('?' * (muscleFilter.length)).split('').join(', ')})",
whereArgs: muscleFilter,
);
final equipmentRes = await db.query(
'exercises',
where: "equipment IN (${('?' * (equipmentFilter.length)).split('').join(', ')})",
whereArgs: equipmentFilter,
);
return finalResult; //need to combine the results with a logical AND somehow
}
I know there's the option the use a rawQuery with logical OR / AND, but that doesn't work for my case.
It should be possible for the user to select different attributes and thus filter the list. Im looking for a way to pass arguments to this function and query my table accordingly to the passed arguments but I already fail when merging the first two queries.
How to add a logical AND to these two queries?
And furthermore: How to add even more attributes with a logical AND and order the final result?

I managed to find a way to the first question:
List<String> muscleFilter = ['Chest', 'Biceps'];
List<String> equipmentFilter = ['Machine', 'Cable'];
return db.rawQuery('''
select * from exercises
where targetMuscle in (${('?' * (muscleFilter.length)).split('').join(', ')})
and equipment in (${('?' * (equipmentFilter.length)).split('').join(', ')})
''',
muscleFilter + equipmentFilter
);

Related

How to rawQuery in multiple columns in Sqflite

I created an onChanged function for a TextFormField to perform a query in multiple columns of a table. I tried to use OR in the WHERE clause, but it does not seem to work since it only returns queries from the first condition (columnOne), and not when I search for items from columnTwo or columnThree. Is there any other way I can achieve this?
onChanged: (String? databaseQuery) async {
Database db = await DatabaseHelper.instance.database;
List<Map> result = await db.rawQuery('SELECT * FROM table WHERE columnOne LIKE ? OR columnTwo LIKE ? OR columnThree LIKE ?', ['%$databaseQuery%']);
_map = result;
setState(() {});
}
Note: What I am trying to accomplish is like a Full Text Search, but I want to do it via rawQuery or query only instead of having to enable FTS. Thanks!
for each ? in the raw Query, you need also a argument
List<Map> result = await db.rawQuery('SELECT * FROM table WHERE columnOne LIKE ? OR columnTwo LIKE ? OR columnThree LIKE ?', ['%$databaseQuery%', '%$databaseQuery%', '%$databaseQuery%']);

Where in clause in Flutter sqflite

I'm trying to use where in clasue but i get this error:
Invalid argument [1, 2, 3] with type List Only num, String and
Uint8List are supported.
My code:
Database db = await instance.database;
List<Map> maps = await db.query('table',
where: 'categoryID in (?)', whereArgs: [ [1,2,3]]);
From this document
Particulary, lists (expect for blob content) are not supported. A
common mistake is to expect to use IN (?) and give a list of values.
This does not work. Instead you should list each argument one by one:
var list = await db.rawQuery('SELECT * FROM my_table WHERE name IN (?, ?, ?)', ['cat', 'dog', 'fish']);
But my categories can change any moment so I cant list each argument one by one.
While I understand that it could sound painful, that is unfortunately the way SQLite works and sqflite does not do any SQL parsing.
You could try the following solution that I personnaly use to build the proper number of ?.
List.filled(inArgsCount, '?').join(',')
For example:
var inArgs = ['cat', 'dog', 'fish'];
var list = await db.query('my_table',
where: 'name IN (${List.filled(inArgs.length, '?').join(',')})',
whereArgs: inArgs);

Query a specific cell of sqflite data table in Flutter

There are already some questions and answers like "query a specific row". But I want a specific cell that means I need a specific row with a specific column from the sqflite data table in Flutter. My table has three columns which are id, fname, fid. But I need only fid. Here is my row selection code:
queryfid() async {
Database db = await DatabaseHelper.instance.database;
List<String> columnsToSelect = [
DatabaseHelper.columnId,
DatabaseHelper.columnfname,
DatabaseHelper.columnfid,
];
String whereString = '${DatabaseHelper.columnId} = ?';
int rowId = 1;
List<dynamic> whereArguments = [rowId];
List<Map> result = await db.query(DatabaseHelper.tableid,
columns: columnsToSelect,
where: whereString,
whereArgs: whereArguments);
result.forEach((row) => print(row));
}

Check which PKs in List of PKs is present within SQFLITE database

For a list of PKs of length k:
listPK = [1,2,3...k]
I'm currently running a for loop, and querying the database k times to check whether the item is present within the database or not.
List<bool> isPresent(List listPK)async{
final db = await database;
List<bool> output = List.filled(listPK.length, false)
for (var i = 0; i<listPk.length; i++){
List<Map> result = await db.query('elements', where: "id = ?", whereArgs: listPk[i]);
if (result[0] != null) {output[i] = true}
}
}
Was wondering if there was a more efficient way to do this. I only want to know if the id is present within the database or not.
Use a WHERE ... IN to check against all the IDs in one call.
String listQuery = listPK.join(', '); // "1, 2, 3, ..., k"
String query = 'SELECT * FROM table_name WHERE id IN ($listQuery);`;
List<Map> result = await db.rawQuery(query);
It would be more efficient to query the database once and get all the id's in the 'elements' table. Once you have all the id's in the 'elements' table you can iterate through and find which id's are present and which are not.

Multiple arguments in sqllite in flutter

I would like to know how to pass multiple arguments to a raw query in sqllite.
My code is below
query() async {
// get a reference to the database
Database db = await DatabaseHelper.instance.database;
// raw query
List<Map> result = await db.rawQuery('SELECT * FROM my_table WHERE name=?', ['Peter']);
// print the results
result.forEach((row) => print(row));
}
In the above code i am passing one argument 'Peter' but what if I want to pass multiple arguments, for example:
List<Map> result = await db.rawQuery('SELECT * FROM my_table WHERE name=? and last_name=? and year=?', ['Peter'], ['Smith'],[2019]);
If I do the code above, I get error "Too many positional arguments: 2 expected, but 4 found." can someone show me how to pass multiple arguments to a query in sqllite flutter?
I'm assuming you're using sqflite.
You need to put all your arguments into one list and not multiple.
The code below should work like this:
List<Map> result = await db.rawQuery(
'SELECT * FROM my_table WHERE name=? and last_name=? and year=?',
['Peter', 'Smith', 2019]
);
For more examples how to use raw queries see their examples on their pub.dev page.
Or if you want to use the query function you can do it like this:
String strVal = 'str';
int intVal = 0;
String likeVal = 'str';
final List<Map<String, dynamic>> maps = await db.query('my_table',
where: "col1 LIKE ? and col2 = ? and col3 = ?",
whereArgs: ['$likeVal%', strVal, intVal],
orderBy: 'id',
limit: 10);