I want to create multiple table in sqflite by calling same function - flutter

I want to create multiple tables in sqflite by calling the same function, cause I want to create multiple playlists, playlist name will be the table name, which came from user input,
for this reason, users call the databaseCreate function in multiple time. But its show some error :
Unhandled Exception: DatabaseException(no such table: sports (code 1
SQLITE_ERROR): , while compiling: INSERT INTO sports (title, link, logo,
playlistName) VALUES (?, ?, NULL, ?)) sql 'INSERT INTO sports (title, link, logo,
playlistName)
Database Create Code :
Future open( String name) async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
final path = join(documentsDirectory.path, 'playlist1.db');
_database = await openDatabase(path, version: 2,
onCreate: (Database db, int version) async {
await db.execute('''
create table $name (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,playlistName TEXT, link TEXT, title TEXT,
logo TEXT)
''');
});
}
Hare's name comes from the user. At a very fast time, it will be okay but for creating a second playlist it will be crashed

You should prefer use parameterized queries:
await db.execute("
create table ? (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,playlistName TEXT, link TEXT, title TEXT,
logo TEXT)
", [name]);
UPDATE
If you need to update the database schema, you need to update the version of the database, like this:
return await openDatabase(
path,
version: 2, // <=== Update (increase) this number
onOpen: (db) {},
onCreate: createDatabase,
onUpgrade: upgradeDatabase,
);
Doing this, you ask SQFLite to update the schema. Use onUpgrade to tell the new schema.
You can also uninstall the app when you are in development stage. In this case, new schema should be in onCreate.
If i resume, onCreate is called once when database is created. And onUpgrade is called each time version is increased.
UPDATE 2
For unknown reasons (haven't search more), execute method does not replace the ? by parameter. Perharps for security reasons. In fact using dynamic table name is not a very good design.
So for achive this, you shoult not use parameterized query like i said previously. You should use a concatened string, like this:
await db.rawQuery(
"create table " +
name +
" ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,playlistName TEXT, link TEXT, title TEXT, logo TEXT)",[]);

Related

How to bulk update SQLite table entries in Flutter

My Flutter app makes use of an SQLite database with multiple tables and Firebase authentication. Some time after publishing the app, I added a User ID column to each table, so that I could ensure that results could be filtered by users and they would only see their own data, should another user log into the app on the same device.
When I created the new column in each table though, for the entries that already existed, I allowed the data in the new column to be null to prevent an error with the database. The problem with that is that users who made the initial calculations where the User ID is null will now 'lose' that data, as it won't show up when I implement filtering with User ID.
What I want to do is bulk-update the null values in that column of each SQLite database table, if a null value exists in that table. The null values should be replaced by the current logged in User ID. I'm not sure of the best way to do this but my idea is something like this, with a database update function after it has been initialised:
Future _update(Database db, int oldVersion, int newVersion) async {
if (oldVersion < newVersion) {
Future<int> updateDB(String value) async {
final db = await instance.database;
return db.update(
values,
value.toJson(),
where: '${ValueFields.id} = ?',
whereArgs: [value.id],
);
}
}
}
Thing is, this doesn't seem to actually work and of course doesn't bulk update all rows in that particular column. Can someone advise on how I can build the bulk update function, to take all null User ID values in a particular table and change them to the current logged in user?
Thank you!
What you are doing is never updating anything if id is null. That is even if null were passed as the id via the whereargs, it would never update any rows as null is considered unique/distinct so will never be the same as another null. Instead you can use IS NULL. If the id is not null then it would not update rows where the id is null.
You can update all in one go if you use, (in SQL)
UPDATE the_table SET the_column = the_value WHERE the_column IS NULL
which I believe would be along the lines of:-
return db.update(
values,
value.toJson(),
where: '${ValueFields.id} IS NULL', /*<<<<< CHANGED WHERE CLAUSE */
whereArgs: [], /*<<<<< CHANGED NO WHERE ARGS*/
);

how to initialize Database variable in flutter app

I'm a beginner in flutter, i want to use SQlite database using sqflite package in my Flutter App, when I declare the _database variable with this syntax static Database _database;, I get a compilation error saying _database must be initialized except I don't know how to initialize it ?
You can initialise a database like this
// Set path of the database
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'demo.db');
// Load the database (or create a new one, if it does not yet exist)
Database database = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
// When creating the db, create the table
await db.execute(
'CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT, value INTEGER, num REAL)');
});
Of course, you will need to modify SQL command depending on your desired database structure.
After initialisation, you can perform all your database operations. But don't forget to close the connection in the end via
await database.close();
More info can be found on the documentation page of the sqflite package. This is often a good place to start your research.

How to insert in multiple tables with a single API call in Supabase

This is the simplified structure of my tables - 2 main tables, one relation table.
What's the best way to handle an insert API for this?
If I just have a Client and Supabase:
- First API call to insert book and get ID
- Second API call to insert genre and get ID
- Third API call to insert book-genre relation
This is what I can think of, but 3 API calls seems wrong.
Is there a way where I can do insert into these 3 tables with a single API call from my client, like a single postgres function that I can call?
Please share a general example with the API, thanks!
Is there any reason you need to do this with a single call? I'm assuming from your structure that you're not going to create a new genre for every book you create, so most of the time, you're just inserting a book record and a book_gen_rel record. In the real world, you're probably going to have books that fall into multiple genres, so eventually you're going to be changing your function to handle the insert of a single book along with multiple genres in a single call.
That being said, there are two ways too approach this. You can make multiple API calls from the client (and there's really no problem doing this -- it's quite common). Second, you could do it all in a single call if you create a PostgreSQL function and call it with .rpc().
Example using just client calls to insert a record in each table:
const { data: genre_data, error: genre_error } = await supabase
.from('genre')
.insert([
{ name: 'Technology' }
]);
const genre_id = genre_data[0].id;
const { data: book_data, error: book_error } = await supabase
.from('book')
.insert([
{ name: 'The Joys of PostgreSQL' }
]);
const book_id = book_data[0].id;
const { data: book_genre_rel_data, error: book_genre_rel_error } = await supabase
.from('book_genre_rel_data')
.insert([
{ book_id, genre_id }
]);
Here's a single SQL statement to insert into the 3 tables at once:
WITH genre AS (
insert into genre (name) values ('horror') returning id
),
book AS (
insert into book (name) values ('my scary book') returning id
)
insert into book_genre_rel (genre_id, book_id)
select genre.id, book.id from genre, book
Now here's a PostgreSQL function to do everything in a single function call:
CREATE OR REPLACE FUNCTION public.insert_book_and_genre(book_name text, genre_name text)
RETURNS void language SQL AS
$$
WITH genre AS (
insert into genre (name) values (genre_name) returning id
),
book AS (
insert into book (name) values (book_name) returning id
)
insert into book_genre_rel (genre_id, book_id)
select genre.id, book.id from genre, book
$$
Here's an example to test it:
select insert_book_and_genre('how to win friends by writing good sql', 'self-help')
Now, if you've created that function (inside the Supabase Query Editor), then you can call it from the client like this:
const { data, error } = await supabase
.rpc('insert_book_and_genre', {book_name: 'how I became a millionaire at age 3', genre_name: 'lifestyle'})
Again, I don't recommend this approach, at least not for the genre part. You should insert your genres first (they probably won't change) and simplify this to just insert a book and a book_genre_rel record.

How to set Autoincrement Id starts with Even Or Odd Number in SQLite With Flutter?

How to set Autoincrement Id starts with Even Or Odd Number in SQLite With Flutter?
As we have solution for MySQL but for SQLite is there any way to set Autoincrement starts with Even Or Odd Numbers
As I know same syntax is used in SQLite so if you know how to do it in MySQL just copy and paste it.
for example this has same syntax as in MySQL.
var database = await openDatabase(
path,
version: 1,
onCreate: (Database db, int version) async {
await db.execute('''
CREATE TABLE $alarm(
$columnId INTEGER PRIMARY KEY AUTOINCREMENT,
$columntitle TEXT NOT NULL,
$columnAlarmId INTEGER,
$columnDateTime TEXT NOT NULL,
$columnDaysOn UINT8LIST
)
''');
},
);
return database;
}

Flutter SQFlite many to many relationship setup

I have a Flutter app that will need two tables, table A and table B, now each item from A has many items from B, and each item from B can belong to many items of A, so it's a many-to-many relationship.
this is the code I've written:
static Future<Database> database() async {
final dbPath = await sql.getDatabasesPath();
return sql.openDatabase(path.join(dbPath, 'my_db.db'),
onCreate: (db, version) {
return db.execute(
'CREATE TABLE A(id INT PRIMARY KEY, title TEXT, description TEXT); CREATE TABLE B(id INT PRIMARY KEY, title TEXT, description TEXT);');
}, version: 1);
}
I'm not doing any kind of relating the two tables to each other, because I don't know how to do that in SQFLite.
Do I need to make a third table?
Any help would be appreciated.
First one thing you should notice is that isn't that different of using just Sql
Assuming you have table A and B you can set up as it follows
Future _create(Database db, int version) async {
await db.execute("""
CREATE TABLE C (
id INTEGER PRIMARY KEY,
A_id INTEGER NOT NULL,
B_id INTEGER NOT NULL,
FOREIGN KEY (A_id) REFERENCES A (id)
ON DELETE NO ACTION ON UPDATE NO ACTION,
FOREIGN KEY (B_id) REFERENCES B (id)
ON DELETE NO ACTION ON UPDATE NO ACTION
)""");
}
And you can other columns as you wish accordingly to a specific use-case