我在 Sqlite 数据库中有一个表,当前它是另一个表中字段的外键。 但是,我需要更改该外键,以便它可以指向多个表。
在下面的例子中,最初我只处理来自地球上某个国家的起源的怪物。 现在,我想添加怪物来自不同星球的可能性。 有没有办法在不添加中间表或重命名表或向“Monster”表或任何其他表添加附加字段的情况下执行此操作?
我想通过修改外键来做到这一点。
CREATE TABLE Monster (
Id INTEGER PRIMARY KEY,
Name VARCHAR NOT NULL UNIQUE,
Origin TEXT,
FOREIGN KEY (Origin) REFERENCES Country(Name) ON UPDATE CASCADE
);
CREATE TABLE Country (
Id INTEGER PRIMARY KEY,
Name VARCHAR NOT NULL UNIQUE,
);
但是,我刚刚发现怪物也可能来自另一个星球,因此“Origin”列需要引用“Country”表或“Planet”表。
CREATE TABLE Planet (
Id INTEGER PRIMARY KEY,
Name VARCHAR NOT NULL UNIQUE,
);
请注意,我在一组不同的表中遇到了类似的情况,但通过使用虚拟列解决了。
CREATE MonsterElectricityPower (
Id INTEGER PRIMARY KEY,
Name VARCHAR NOT NULL UNIQUE
);
CREATE MonsterFreezePower (
Id INTEGER PRIMARY KEY,
Name VARCHAR NOT NULL UNIQUE
);
CREATE MonsterPowerParameter (
Id INTEGER PRIMARY KEY,
Level INTEGER,
ParentCode TEXT,
ParentName TEXT,
ParentCode$MonsterElectricityPower TEXT generated always as (case when ParentCode = 'MonsterElectricityPower' then ParentName else NULL end) virtual REFERENCES MonsterElectricityPower (Name) ON DELETE CASCADE,
ParentCode$MonsterFreezePower TEXT generated always as (case when ParentCode = 'MonsterFreezePower' then ParentName else NULL end) virtual REFERENCES MonsterFreezePower(Name) ON DELETE CASCADE
);
这里,ParentCode 指示需要引用哪些表/列,因此我可以相应地创建我的虚拟列。
但是,在上面的第一种情况下,我无法从 Monster 表中知道 Origin 列是否应该引用 Country 表或 Planet 表中的记录。
我无法从 Monster 表中知道 Origin 列是否应该引用 Country 表或 Planet 表中的记录。
你会的。
考虑以下事项(根据您问题中的表格):-
INSERT INTO country (name) VALUES
('England'),('Australia'),('France'),('Spain'),('Germany'),('Pluto') /*<<<< PLUTO PURPOSEFULLY AMBIGUOUS */
;
INSERT INTO planet (name) VALUES
('Mars'),('Saturn'),('Jupiter'),('Venus'),('Pluto') /*<<<< AGAIN PLUTO PURPOSEFULLY AMBIGUOUS */
;
INSERT INTO Monster (name,origin) VALUES
('Monster 1','Australia')
,('Monster 2','Venus')
,('Monster 3','Pluto')
, ('Monster from nowhere!!!!','Timbuktu')
;
SELECT
monster.*,
/* know whether planet, country,both (country and planet), or neither(nowhere) */
CASE
WHEN origin IN (SELECT name FROM country) AND origin IN (SELECT name from planet) THEN 'country and planet'
WHEN origin IN (SELECT name FROM country) THEN 'country'
WHEN origin IN (SELECT name FROM planet) THEN 'Planet'
ELSE 'nowhere'
END AS type
/* get both together */
,coalesce((SELECT name FROM country AS c WHERE c.name=origin),'')||coalesce((SELECT name FROM planet AS p WHERE p.name=origin),'') AS combined
/* get both individually */
,(SELECT name FROM country AS c WHERE c.name=origin) AS country_of_origin
,(SELECT name FROM planet AS p WHERE p.name=origin) AS planet_of_origin
FROM Monster;
这会导致:-
因此可以确定是哪一个、两者都存在或都没有。
如果存在参考,也可以仅插入一个怪物,也许可以考虑以下尝试插入 4 个怪物的方法
not a country or planet
) 既不指向国家,也不指向行星按照:-
WITH
cte_insert_data(monster,origin) AS (
SELECT 'monsterx','not a country or planet'
UNION SELECT 'monstera','England'
UNION SELECT 'montserb','Venus'
UNION SELECT 'monstery','Pluto'
),
cte_to_insert_monster(monster,origin,in_country,in_planet) AS (
SELECT
monster,
origin,
origin IN (SELECT name FROM country AS c WHERE c.name=origin),
origin IN (SELECT name FROM planet AS p WHERE p.name=origin)
FROM cte_insert_data
)
INSERT INTO monster (name,origin)
SELECT monster,origin
FROM cte_to_insert_monster
WHERE (in_country OR in_planet)
AND NOT (in_country AND in_planet) /* to exclude insertion of ambiguous (Pluto) if required */;
SELECT * FROM monster;
随后 SELECT 的结果是:-