【发布时间】:2021-07-04 10:50:19
【问题描述】:
考虑我的汽车租赁公司,有两种不同的租赁车辆:
CREATE TABLE busses (
id INTEGER PRIMARY KEY NOT NULL,
places INTEGER NOT NULL
);
CREATE TABLE cars (
id INTEGER PRIMARY KEY NOT NULL,
places INTEGER NOT NULL
);
CREATE TABLE vehicles (
id INTEGER PRIMARY KEY NOT NULL,
bus_id INTEGER,
car_id INTEGER,
FOREIGN KEY(bus_id) REFERENCES busses(id),
FOREIGN KEY(car_id) REFERENCES cars(id),
CHECK (NOT(bus_id IS NULL AND car_id IS NULL))
);
CREATE TABLE rentals(
id INTEGER PRIMARY KEY NOT NULL,
vehicle_id INTEGER NOT NULL,
customer_id INTEGER NOT NULL,
FOREIGN KEY(vehicle_id) REFERENCES vehicles(id)
);
我的汽车公司在过去几年做得很好。我们已经订购了几辆卡车,我们也计划将它们出租。我们想要得到这个架构:
CREATE TABLE busses (..);
CREATE TABLE cars (..);
CREATE TABLE trucks (
id INTEGER PRIMARY KEY NOT NULL,
tar_weight INTEGER NOT NULL,
max_net_weight INTEGER NOT NULL
);
CREATE TABLE vehicles (
id INTEGER PRIMARY KEY NOT NULL,
bus_id INTEGER,
car_id INTEGER,
truck_id INTEGER,
FOREIGN KEY(bus_id) REFERENCES busses(id),
FOREIGN KEY(car_id) REFERENCES cars(id),
FOREIGN KEY(truck_id) REFERENCES trucks(id),
CHECK (NOT(bus_id IS NULL AND car_id IS NULL AND truck_id IS NULL))
);
CREATE TABLE rentals(...);
在普通 SQL 中,您可以使用 ALTER TABLE 在这两个模式之间移动。但是,SQLite 似乎不允许重写 CHECK 约束(例如 How do I DROP a constraint from a sqlite (3.6.21) table?),也不允许删除它并重新添加它。
解决办法是
- 重命名表;那么
- 用新的
CHECK约束重新创建新表;那么 - 重新插入旧表中的数据。
类似
ALTER TABLE vehicles RENAME TO vehicles_old;
CREATE TABLE vehicles (...);
INSERT INTO vehicles (id, bus_id, car_id) SELECT * FROM vehicles_old;
DROP TABLE vehicles_old;
但是,将vehicles 表重命名为vehicles_old 也会重命名busses 和cars 附带的FOREIGN KEY 约束:重命名后它们指向vehicles_old 表,如下所示:
sqlite> select * from sqlite_schema;
table|busses|busses|2|CREATE TABLE busses (
id INTEGER PRIMARY KEY NOT NULL,
places INTEGER NOT NULL
)
table|cars|cars|3|CREATE TABLE cars (
id INTEGER PRIMARY KEY NOT NULL,
places INTEGER NOT NULL
)
table|rentals|rentals|5|CREATE TABLE rentals(
id INTEGER PRIMARY KEY NOT NULL,
vehicle_id INTEGER NOT NULL,
customer_id INTEGER NOT NULL,
FOREIGN KEY(vehicle_id) REFERENCES "vehicles_old"(id)
)
table|trucks|trucks|6|CREATE TABLE trucks (
id INTEGER PRIMARY KEY NOT NULL,
tar_weight INTEGER NOT NULL,
max_net_weight INTEGER NOT NULL
)
table|vehicles|vehicles|7|CREATE TABLE vehicles (
id INTEGER PRIMARY KEY NOT NULL,
bus_id INTEGER,
car_id INTEGER,
truck_id INTEGER,
FOREIGN KEY(bus_id) REFERENCES busses(id),
FOREIGN KEY(car_id) REFERENCES cars(id),
FOREIGN KEY(truck_id) REFERENCES trucks(id),
CHECK (NOT(bus_id IS NULL AND car_id IS NULL AND truck_id IS NULL))
)
我现在的问题是:如何重新设置 rentals 表的父级,使其指向 vehicles 表而不是不存在的 vehicles_old 表?
注意,这可能被认为是一个 x-y 问题,其中“y”是“rentals 的重新父母化?”,“x”是“我如何更新 vehicles 的检查约束?”。我认为后者是不可能的。
这不应该被认为是一个 x-y-z 问题,我应该介绍一个 vehicle_types 和 vehicle_attributes 表; in my real case 我们说的是 ISA 关系。
【问题讨论】:
标签: sqlite database-design database-migration