Related
I haven't been able to find a solution that works for me yet. Whenever I try to apply an alias to a column the column in question is omitted in the return value, all other fields are returned as expected and I've tried various different ways.
export class LeadsData {
constructor(
#InjectRepository(LeadsData, 'leads-legacy')
private readonly leadsDataRepo: Repository<LeadsData>
) {}
public async getData(lead: number): Promise<any> {
const q = await this.leadsDataRepo
.createQueryBuilder('leads-data')
.select('leads-data.user', 'updatedByUser')
.where('leads-data.lead = :lead', { lead })
.getMany()
console.log(q)
return q
}
}
this generates the following sql query:
SELECT `leads-data`.`user` AS 'updateByUser' FROM `leads-data` `leads-data` WHERE `leads-data`.`lead` = ?
When executing the raw query within the database I get the correct results to the query
however, the resulting payload from the query is []
from what I've read in the docs this should work
I should also clarify that if other columns are included then those columns are returned.
I`m trying to insert data from a json object ,the following code is a bout the table I used
I defined the database helper class like this:
class DatabaseHelper {
static DatabaseHelper _databaseHelper; // Singleton DatabaseHelper
static Database _database; // Singleton Database
String category_Table = 'category_Table';
String category_id = 'category_id';
String device_type_id = 'device_type_id';
String room_id = 'room_id ';
...
await db.execute(
'CREATE TABLE $category_Table($category_id INTEGER PRIMARY KEY UNIQUE , $device_type_id INTEGER, '
'$room_id INTEGER)');
print('category created!');
and here is the insert function
Database db = await this.database;
var result = await db.insert(category_Table, category.toMap());
print('category inserted');
return result;
}
here is the Error
Exception has occurred.
SqfliteDatabaseException (DatabaseException(table category_Table has no column named category_id (code 1): , while compiling: INSERT INTO category_Table (category_id, device_type_id, room_id) VALUES (?, ?, ?)) sql 'INSERT INTO category_Table (category_id, device_type_id, room_id) VALUES (?, ?, ?)' args [1, 1, 1]})
thanks for any helps:)
1) Firstly check if the same variable text you use in your model, Map is the same name with your column
2) update the Database version number
3) Uninstall and reinstall the App on your phone or emulator.
For me, the error was because of missing comma and space after the previous column.
What I had:
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
final String categoryTable = "categoryTable";
final String idColumn = "idColumn";
final String nameColumn = "nameColumn";
final String weightColumn = "weightColumn";
final String typeColumn = "typeColumn";
final String gradeColumn = "gradeColumn";
final String professorColumn = "professorColumn";
final String colorColumn = "colorColumn";
db.execute(
"CREATE TABLE $categoryTable("
"$idColumn INTEGER PRIMARY KEY, "
"$nameColumn TEXT, "
"$weightColumn NUMERIC, "
"$typeColumn NUMERIC" // <- missing comma and space
"$professorColumn TEXT, " // Error when I try to add something to this column
"$colorColumn TEXT)"
);
What solved for me was:
db.execute(
"CREATE TABLE $categoryTable("
"$idColumn INTEGER PRIMARY KEY, "
"$nameColumn TEXT, "
"$weightColumn NUMERIC, "
"$typeColumn NUMERIC, " // <- Fixed the error
"$professorColumn TEXT, "
"$colorColumn TEXT)"
);
I encountered this problem and i tried whole different sort of things but finally, what worked for me is written below
Step 1 : Change the database version number
Earlier it was like this
static final dbVersion = 1;
I later changed it to
static final dbVersion = 5;
This is the function where I initialized the database. I was creating a table with four columns viz id, title, description, and date.
Future _initDatabase() async {
Directory _directory = await getApplicationDocumentsDirectory();
var path = join(_directory.path, dbName);
print(path);
return await openDatabase(path, version: dbVersion,//here is the dbVersion
onCreate: (Database db, int dbVersion) async {
await db.execute(
'CREATE TABLE $table($colId INTEGER PRIMARY KEY AUTOINCREMENT, $colTitle TEXT, $colDescription TEXT, $colDate TEXT)');
});
}
Step 2: Clear all the app data and then re run the app.
I hope your problem will get solved :)
the variables I used toMAP method was not as same as the database helper class in dictation
Try to delete the application storage and reinstall it,as maybe you already created the database file on your phone in a wrong or old way or even a missing column. A fresh start might work if you properly used SQFLite.
Check if the DB generated was generated with all fields declared. In negative case, you can just delete the DB and run query to create the tables.
Work here in this way
I'm trying to query a Companies table using the companyName, I want to get the companies whose companyName(s) contains a query string, not only the companies whose companyName are exact matches of my query strings. If I was using sql, I would use the
---WHERE companyName LIKE %queryString% statement.
So my question is how do I make such a query in sqflite?
Right now I am getting a syntax error because of the %
Table Structure
CREATE TABLE Companies(
id INTEGER PRIMARY KEY,
name TEXT,
email TEXT,
website TEXT,
about TEXT,
phone TEXT,
logo TEXT,
created_at TEXT
);
);
Code for searching
Future<List<CompanyModel>> filterCompanies(String filterCriteria) async {
final db =await database;
List<CompanyModel> filteredCompanies = [];
var res = await db.rawQuery("SELECT * FROM Companies WHERE name LIKE %?%;", [filterCriteria]);
if(res.length !=null){
for (var item in res){
filteredCompanies.add(JobModel.fromDb(item));
}
}
return filteredCompanies;
}
When I add the %, I get a syntax error.
The accepted answer leads to build error for me. I'm using sqflite: ^1.1.7+1 with flutter: v1.13.5.
From the discussion below, it comes out the percent character should be in the parameter instead of in the query, i.e.,
res = await db.query(
"Companies",
where: "name LIKE ?"
whereArgs: ['%$title']
);
Ref: https://github.com/tekartik/sqflite/issues/316
I tried all of the answers above but not worked. Finally:
await db.query(
"Companies",
where: "name LIKE ?",
whereArgs: ['%$query%']
);
The below code works:
var res = await db.rawQuery("SELECT * FROM Companies WHERE name LIKE '%$filterCriteria%'");
This is the code that ended up working perfectly for me.
res = await db.query(
"Companies",
where: "name LIKE '%$?%'"
whereArgs: [title]
);
You have to use this syntax : LIKE " searched string "
Here is an example :
var res = await db.rawQuery(' SELECT * FROM Companies WHERE name LIKE "%$filterCriteria%"
');
It works with flutter and sqflite
Use this
var res = await db.rawQuery("SELECT * FROM Companies WHERE name LIKE '%?%';", [filterCriteria]);
Instead of
var res = await db.rawQuery("SELECT * FROM Companies WHERE name LIKE %?%;", [filterCriteria]);
put like condition in single quote('...')
this works for me
var res = await db.rawQuery("SELECT * FROM Companies WHERE name LIKE ?",['%$filterCriteria%']);
From the docs:
You can also chain multiple where() methods to create more specific queries (logical AND).
How can I perform an OR query?
Example:
Give me all documents where the field status is open OR upcoming
Give me all documents where the field status == open OR createdAt <= <somedatetime>
OR isn't supported as it's hard for the server to scale it (requires keeping state to dedup). The work around is to issue 2 queries, one for each condition, and dedup on the client.
Edit (Nov 2019):
Cloud Firestore now supports IN queries which are a limited type of OR query.
For the example above you could do:
// Get all documents in 'foo' where status is open or upcmoming
db.collection('foo').where('status','in',['open','upcoming']).get()
However it's still not possible to do a general OR condition involving multiple fields.
With the recent addition of IN queries, Firestore supports "up to 10 equality clauses on the same field with a logical OR"
A possible solution to (1) would be:
documents.where('status', 'in', ['open', 'upcoming']);
See Firebase Guides: Query Operators | in and array-contains-any
suggest to give value for status as well.
ex.
{ name: "a", statusValue = 10, status = 'open' }
{ name: "b", statusValue = 20, status = 'upcoming'}
{ name: "c", statusValue = 30, status = 'close'}
you can query by ref.where('statusValue', '<=', 20) then both 'a' and 'b' will found.
this can save your query cost and performance.
btw, it is not fix all case.
I would have no "status" field, but status related fields, updating them to true or false based on request, like
{ name: "a", status_open: true, status_upcoming: false, status_closed: false}
However, check Firebase Cloud Functions. You could have a function listening status changes, updating status related properties like
{ name: "a", status: "open", status_open: true, status_upcoming: false, status_closed: false}
one or the other, your query could be just
...where('status_open','==',true)...
Hope it helps.
This doesn't solve all cases, but for "enum" fields, you can emulate an "OR" query by making a separate boolean field for each enum-value, then adding a where("enum_<value>", "==", false) for every value that isn't part of the "OR" clause you want.
For example, consider your first desired query:
Give me all documents where the field status is open OR upcoming
You can accomplish this by splitting the status: string field into multiple boolean fields, one for each enum-value:
status_open: bool
status_upcoming: bool
status_suspended: bool
status_closed: bool
To perform your "where status is open or upcoming" query, you then do this:
where("status_suspended", "==", false).where("status_closed", "==", false)
How does this work? Well, because it's an enum, you know one of the values must have true assigned. So if you can determine that all of the other values don't match for a given entry, then by deduction it must match one of the values you originally were looking for.
See also
in/not-in/array-contains-in: https://firebase.google.com/docs/firestore/query-data/queries#in_and_array-contains-any
!=: https://firebase.googleblog.com/2020/09/cloud-firestore-not-equal-queries.html
I don't like everyone saying it's not possible.
it is if you create another "hacky" field in the model to build a composite...
for instance, create an array for each document that has all logical or elements
then query for .where("field", arrayContains: [...]
you can bind two Observables using the rxjs merge operator.
Here you have an example.
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/merge';
...
getCombinatedStatus(): Observable<any> {
return Observable.merge(this.db.collection('foo', ref => ref.where('status','==','open')).valueChanges(),
this.db.collection('foo', ref => ref.where('status','==','upcoming')).valueChanges());
}
Then you can subscribe to the new Observable updates using the above method:
getCombinatedStatus.subscribe(results => console.log(results);
I hope this can help you, greetings from Chile!!
We have the same problem just now, luckily the only possible values for ours are A,B,C,D (4) so we have to query for things like A||B, A||C, A||B||C, D, etc
As of like a few months ago firebase supports a new query array-contains so what we do is make an array and we pre-process the OR values to the array
if (a) {
array addObject:#"a"
}
if (b) {
array addObject:#"b"
}
if (a||b) {
array addObject:#"a||b"
}
etc
And we do this for all 4! values or however many combos there are.
THEN we can simply check the query [document arrayContains:#"a||c"] or whatever type of condition we need.
So if something only qualified for conditional A of our 4 conditionals (A,B,C,D) then its array would contain the following literal strings: #["A", "A||B", "A||C", "A||D", "A||B||C", "A||B||D", "A||C||D", "A||B||C||D"]
Then for any of those OR combinations we can just search array-contains on whatever we may want (e.g. "A||C")
Note: This is only a reasonable approach if you have a few number of possible values to compare OR with.
More info on Array-contains here, since it's newish to firebase docs
If you have a limited number of fields, definitely create new fields with true and false like in the example above. However, if you don't know what the fields are until runtime, you have to just combine queries.
Here is a tags OR example...
// the ids of students in class
const students = [studentID1, studentID2,...];
// get all docs where student.studentID1 = true
const results = this.afs.collection('classes',
ref => ref.where(`students.${students[0]}`, '==', true)
).valueChanges({ idField: 'id' }).pipe(
switchMap((r: any) => {
// get all docs where student.studentID2...studentIDX = true
const docs = students.slice(1).map(
(student: any) => this.afs.collection('classes',
ref => ref.where(`students.${student}`, '==', true)
).valueChanges({ idField: 'id' })
);
return combineLatest(docs).pipe(
// combine results by reducing array
map((a: any[]) => {
const g: [] = a.reduce(
(acc: any[], cur: any) => acc.concat(cur)
).concat(r);
// filter out duplicates by 'id' field
return g.filter(
(b: any, n: number, a: any[]) => a.findIndex(
(v: any) => v.id === b.id) === n
);
}),
);
})
);
Unfortunately there is no other way to combine more than 10 items (use array-contains-any if < 10 items).
There is also no other way to avoid duplicate reads, as you don't know the ID fields that will be matched by the search. Luckily, Firebase has good caching.
For those of you that like promises...
const p = await results.pipe(take(1)).toPromise();
For more info on this, see this article I wrote.
J
OR isn't supported
But if you need that you can do It in your code
Ex : if i want query products where (Size Equal Xl OR XXL : AND Gender is Male)
productsCollectionRef
//1* first get query where can firestore handle it
.whereEqualTo("gender", "Male")
.addSnapshotListener((queryDocumentSnapshots, e) -> {
if (queryDocumentSnapshots == null)
return;
List<Product> productList = new ArrayList<>();
for (DocumentSnapshot snapshot : queryDocumentSnapshots.getDocuments()) {
Product product = snapshot.toObject(Product.class);
//2* then check your query OR Condition because firestore just support AND Condition
if (product.getSize().equals("XL") || product.getSize().equals("XXL"))
productList.add(product);
}
liveData.setValue(productList);
});
For Flutter dart language use this:
db.collection("projects").where("status", whereIn: ["public", "unlisted", "secret"]);
actually I found #Dan McGrath answer working here is a rewriting of his answer:
private void query() {
FirebaseFirestore db = FirebaseFirestore.getInstance();
db.collection("STATUS")
.whereIn("status", Arrays.asList("open", "upcoming")) // you can add up to 10 different values like : Arrays.asList("open", "upcoming", "Pending", "In Progress", ...)
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot queryDocumentSnapshots, #Nullable FirebaseFirestoreException e) {
for (DocumentSnapshot documentSnapshot : queryDocumentSnapshots) {
// I assume you have a model class called MyStatus
MyStatus status= documentSnapshot.toObject(MyStatus.class);
if (status!= null) {
//do somthing...!
}
}
}
});
}
This query produces an error No value given for one or more required parameters:
using (var conn = new OleDbConnection("Provider=..."))
{
conn.Open();
var result = conn.Query(
"select code, name from mytable where id = ? order by name",
new { id = 1 });
}
If I change the query string to: ... where id = #id ..., I will get an error: Must declare the scalar variable "#id".
How do I construct the query string and how do I pass the parameter?
The following should work:
var result = conn.Query(
"select code, name from mytable where id = ?id? order by name",
new { id = 1 });
Important: see newer answer
In the current build, the answer to that would be "no", for two reasons:
the code attempts to filter unused parameters - and is currently removing all of them because it can't find anything like #id, :id or ?id in the sql
the code for adding values from types uses an arbitrary (well, ok: alphabetical) order for the parameters (because reflection does not make any guarantees about the order of members), making positional anonymous arguments unstable
The good news is that both of these are fixable
we can make the filtering behaviour conditional
we can detect the category of types that has a constructor that matches all the property names, and use the constructor argument positions to determine the synthetic order of the properties - anonymous types fall into this category
Making those changes to my local clone, the following now passes:
// see https://stackoverflow.com/q/18847510/23354
public void TestOleDbParameters()
{
using (var conn = new System.Data.OleDb.OleDbConnection(
Program.OleDbConnectionString))
{
var row = conn.Query("select Id = ?, Age = ?", new DynamicParameters(
new { foo = 12, bar = 23 } // these names DO NOT MATTER!!!
) { RemoveUnused = false } ).Single();
int age = row.Age;
int id = row.Id;
age.IsEqualTo(23);
id.IsEqualTo(12);
}
}
Note that I'm currently using DynamicParameters here to avoid adding even more overloads to Query / Query<T> - because this would need to be added to a considerable number of methods. Adding it to DynamicParameters solves it in one place.
I'm open to feedback before I push this - does that look usable to you?
Edit: with the addition of a funky smellsLikeOleDb (no, not a joke), we can now do this even more directly:
// see https://stackoverflow.com/q/18847510/23354
public void TestOleDbParameters()
{
using (var conn = new System.Data.OleDb.OleDbConnection(
Program.OleDbConnectionString))
{
var row = conn.Query("select Id = ?, Age = ?",
new { foo = 12, bar = 23 } // these names DO NOT MATTER!!!
).Single();
int age = row.Age;
int id = row.Id;
age.IsEqualTo(23);
id.IsEqualTo(12);
}
}
I've trialing use of Dapper within my software product which is using odbc connections (at the moment). However one day I intend to move away from odbc and use a different pattern for supporting different RDBMS products. However, my problem with solution implementation is 2 fold:
I want to write SQL code with parameters that conform to different back-ends, and so I want to be writing named parameters in my SQL now so that I don't have go back and re-do it later.
I don't want to rely on getting the order of my properties in line with my ?. This is bad. So my suggestion is to please add support for Named Parameters for odbc.
In the mean time I have hacked together a solution that allows me to do this with Dapper. Essentially I have a routine that replaces the named parameters with ? and also rebuilds the parameter object making sure the parameters are in the correct order.
However looking at the Dapper code, I can see that I've repeated some of what dapper is doing anyway, effectively it each parameter value is now visited once more than what would be necessary. This becomes more of an issue for bulk updates/inserts.
But at least it seems to work for me o.k...
I borrowed a bit of code from here to form part of my solution...
The ? for parameters was part of the solution for me, but it only works with integers, like ID. It still fails for strings because the parameter length isn't specifed.
OdbcException: ERROR [HY104] [Microsoft][ODBC Microsoft Access Driver]Invalid precision value
System.Data.Odbc. OdbcParameter.Bind(OdbcStatementHandle hstmt,
OdbcCommand command, short ordinal, CNativeBuffer parameterBuffer, bool allowReentrance)
System.Data.Odbc.OdbcParameterCollection.Bind(OdbcCommand command, CMDWrapper cmdWrapper, CNativeBuffer parameterBuffer)
System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior behavior, string method, bool needReader, object[] methodArguments, SQL_API odbcApiMethod)
System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior behavior, string method, bool needReader)
System.Data.Common.DbCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
Dapper.SqlMapper.QueryAsync(IDbConnection cnn, Type effectiveType, CommandDefinition command) in SqlMapper.Async.cs
WebAPI.DataAccess.CustomerRepository.GetByState(string state) in Repository.cs
var result = await conn.QueryAsync(sQuery, new { State = state });
WebAPI.Controllers.CustomerController.GetByState(string state) in CustomerController .cs
return await _customerRepo.GetByState(state);
For Dapper to pass string parameters to ODBC I had to specify the length.
var result = await conn.QueryAsync<Customer>(sQuery, new { State = new DbString { Value = state, IsFixedLength = true, Length = 4} });