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
Related
I created a new int8 column (id_int8) for a table and copied all of the ids into the column. I'd now like to write a migration that will rename the new column to id and delete the old id column. But I've gotten the error ERROR: Unknown constraint error.
import { QueryInterface } from 'sequelize';
export default {
up: async (queryInterface: QueryInterface): Promise<void> => {
await queryInterface.sequelize.query(
`
BEGIN;
LOCK TABLE table IN EXCLUSIVE MODE;
ALTER TABLE table DROP CONSTRAINT table_pkey, ADD CONSTRAINT table_pkey PRIMARY KEY USING INDEX id_int8_unique;
ALTER SEQUENCE table_id_seq OWNED BY table.id_int8;
ALTER TABLE table ALTER COLUMN id_int8 SET DEFAULT nextval('table_id_seq');
ALTER TABLE table DROP COLUMN id;
ALTER TABLE table RENAME COLUMN id_int8 TO id;
COMMIT;
`,
);
},
down: async (): Promise<void> => {
// no-op transaction
},
};
I can see that I have the index "table_pkey" PRIMARY KEY, btree (id)
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)",[]);
I have the following nodejs code (simplified):
// tables
CREATE TABLE admins (
admin_id bigint DEFAULT nextval('admins_seq') NOT NULL,
username character varying(25) NOT NULL,
password character varying(150) NOT NULL
);
CREATE TABLE admin_notifications (
admin_notification_id bigint DEFAULT nextval('admin_notifications_seq') NOT NULL,
admin_id bigint NOT NULL,
type character varying(150) NOT NULL
);
ALTER TABLE admin_notifications ADD CONSTRAINT admin_notifications_to_admins_fk FOREIGN KEY (admin_id) REFERENCES admins(admin_id) ON DELETE CASCADE;
await client.query('BEGIN');
// create a new array in the database and return the newly created admin id
const query = 'INSERT INTO admins (username, password) VALUES($1,$2) RETURNING admin_id';
const values = [];
const result = await client.query(query, values);
// insert a welcome notification for the newly created admin
const query2 = 'INSERT INTO admin_notifications (admin_id, type) VALUES ($1,$2)';
const values2 = [result.rows[0].admin_id, 'welcome'];
const result2 = await client.query(query2, values2);
await client.query('COMMIT');
A little explanation: i create a new admin in the table admins. When a new admin is created, I want to insert a new welcome notification in the table admin_notifications. The column admin_id in the table admin_notifications is a foreign key to the table admins (admin_id).
I get the following error:
Error: insert or update on table "admin_notifications" violates foreign key constraint "admin_notifications_to_admins_fk"
When I leave out the transactions it works?!
Does it has something to do with deferring constraints? And how to handle this in my code?
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;
}
I have some problem. I want to add new column into my table that references to other column in other table. I do something like that:
class m161202_153033_dodanie_informacji_o_obsludze_prawnej_do_pozyczki extends CDbMigration
{
public function safeUp()
{
$this->execute("ALTER TABLE loan ADD COLUMN administrator int NOT NULL DEFAULT 15 REFERENCES person (id) ON UPDATE CASCADE ON DELETE NO ACTION;");
}
public function safeDown()
{
$this->execute("ALTER TABLE loan DROP COLUMN administrator;");
}
}
But when i try to execute this migration i have this error:
Foreign key violation: 7
DETAIL: Key (administrator)=(15) doesn't appear in table "person"..
I know that there is no suck column "administrator" in my table. But i want to add new column "administrator" into loan table. I wanted to make "administrator" foreign key from person table, column "id". Can u help me, what am i doing wrong?
The error means that there is no row in person with id equal to 15, which would be required for the constraint to be fulfilled.
When you run that ALTER TABLE statement, the table has to be rewritten, and the new column is filled with the value 15.
Often it is easier to create a new column nullable and without default value (then ALTER TABLE will not rewrite the table) and use UPDATE to populate the new column. After that you can change the column definition to NOT NULL and add a default value.
Try this
class m161202_153033_dodanie_informacji_o_obsludze_prawnej_do_pozyczki extends CDbMigration
{
public function safeUp()
{
$this->execute("INSERT INTO person (id) VALUES (15) ON CONFLICT (id) DO NOTHING;");
$this->execute("ALTER TABLE loan ADD COLUMN administrator int NOT NULL DEFAULT 15 REFERENCES person (id) ON UPDATE CASCADE ON DELETE NO ACTION;");
}
public function safeDown()
{
$this->execute("ALTER TABLE loan DROP COLUMN administrator;");
}
}