Внешний ключ SQLite в C++
Ограничение FOREIGN KEY задает ссылку зависимой таблицы на первичный ключ родителя.
В SQLite проверка срабатывает только после
PRAGMA foreign_keys = ON на соединении.
Таблица складов и ячеек с явной ссылкой на родителя
создается так:
#include <iostream>
#include <sqlite3.h>
int main() {
sqlite3* db = nullptr;
if (sqlite3_open("fk_bins.db", &db) != SQLITE_OK) {
std::cerr << sqlite3_errmsg(db) << "\n";
sqlite3_close(db);
return 1;
}
sqlite3_exec(
db, "PRAGMA foreign_keys = ON",
nullptr, nullptr, nullptr
);
sqlite3_exec(
db,
"CREATE TABLE IF NOT EXISTS warehouses ("
"id INTEGER PRIMARY KEY, code TEXT NOT NULL)",
nullptr, nullptr, nullptr
);
sqlite3_exec(
db,
"CREATE TABLE IF NOT EXISTS bins ("
"id INTEGER PRIMARY KEY, "
"warehouse_id INTEGER NOT NULL, label TEXT NOT NULL, "
"FOREIGN KEY (warehouse_id) REFERENCES warehouses (id))",
nullptr, nullptr, nullptr
);
sqlite3_stmt* parent = nullptr;
sqlite3_prepare_v2(
db, "INSERT INTO warehouses (code) VALUES (?)",
-1, &parent, nullptr
);
sqlite3_bind_text(parent, 1, "W1", -1, SQLITE_STATIC);
sqlite3_step(parent);
sqlite3_finalize(parent);
sqlite3_stmt* child = nullptr;
sqlite3_prepare_v2(
db,
"INSERT INTO bins (warehouse_id, label) VALUES (?, ?)",
-1, &child, nullptr
);
sqlite3_bind_int(child, 1, 1);
sqlite3_bind_text(child, 2, "A-01", -1, SQLITE_STATIC);
sqlite3_step(child);
std::cout << sqlite3_changes(db) << "\n";
sqlite3_finalize(child);
sqlite3_close(db);
return 0;
}
Число в warehouse_id должно совпадать с
существующим id склада. Иначе шаг вставки
вернет код ограничения, а не SQLITE_DONE:
#include <iostream>
#include <sqlite3.h>
int main() {
sqlite3* db = nullptr;
if (sqlite3_open("fk_bins.db", &db) != SQLITE_OK) {
std::cerr << sqlite3_errmsg(db) << "\n";
sqlite3_close(db);
return 1;
}
sqlite3_exec(
db, "PRAGMA foreign_keys = ON",
nullptr, nullptr, nullptr
);
sqlite3_exec(
db,
"CREATE TABLE IF NOT EXISTS warehouses ("
"id INTEGER PRIMARY KEY, code TEXT NOT NULL)",
nullptr, nullptr, nullptr
);
sqlite3_exec(
db,
"CREATE TABLE IF NOT EXISTS bins ("
"id INTEGER PRIMARY KEY, "
"warehouse_id INTEGER NOT NULL, label TEXT NOT NULL, "
"FOREIGN KEY (warehouse_id) REFERENCES warehouses (id))",
nullptr, nullptr, nullptr
);
sqlite3_stmt* bad = nullptr;
sqlite3_prepare_v2(
db,
"INSERT INTO bins (warehouse_id, label) VALUES (?, ?)",
-1, &bad, nullptr
);
sqlite3_bind_int(bad, 1, 99);
sqlite3_bind_text(bad, 2, "ghost", -1, SQLITE_STATIC);
int rc = sqlite3_step(bad);
if (rc != SQLITE_DONE) {
std::cout << "rejected\n";
}
sqlite3_finalize(bad);
sqlite3_close(db);
return 0;
}
В fk_bins.db добавьте склад "W2"
и ячейку "B-02" с корректным
warehouse_id. Выведите число затронутых
строк при вставке ячейки через
sqlite3_changes.
Попробуйте вставить ячейку с warehouse_id
500. Если шаг вставки не завершился
SQLITE_DONE, выведите "bad link".
Создайте в новом файле fk_rooms.db
таблицы buildings и rooms со
ссылкой на здание. Добавьте здание и комнату с
валидным ключом.