原始问题
所以我没有创建的商业模型有一个可选的关系(就像在 ER 模型中一样)。自从我在 DB 工作以来已经有一段时间了,所以我可能会忘记一些事情。目前第一张表的FK(Foreign Key)指向第二张表的PK(Primary Key),是一个ID;我不记得这个术语,但它是“假”的,而不是 RDBMS(关系数据库管理系统)使用的“真实”。为简单起见,让我们假设只有 2 个表。
目前,当不需要可选关系时,我在 FK 列/属性中有空值。当该列中有一个项目时,我想要充分的优势,检查关系的另一端是否有匹配的项目,FK 指向(第二个表),也触发(虽然目前没有)和其他验证。直到不久前,当我意识到我不想在第一个表的重要部分上重复时,我都很满意,所以我想创建一个唯一键,但似乎无法创建一个键,其中包含一个列/属性可能包含 null。到目前为止,向我提出了 2 个解决方案,尽管我都不明白。
第一个是我设置默认值,基于数字的类型为 0,基于字符的类型为空字符串 ('')。我没有得到的是第二个表已经有一个具有相应值(0)的行/元组。如果我要将当前行转换为没有默认行,我假设我也会将相应的内容放入默认值,在我的情况下它是基于字符的类型。因此,启用索引的“成本”将是进行大量无用的连接,然后通过软件进行大量无用的合并,在我的例子中,是办公套件Apache OpenOffice Base的数据库部分。这似乎增加了很多处理,在我看来,某种触发器以及我当前的设计会更好。
第二个是制作一个“链接”表(他/她的任期),一个多对多的关系,但我认为这些仅适用于具有超过 1 个可能关系的条目;具有0-1关系的人不会使用它。无论如何,我仍然会遇到同样的问题,在那个“链接”表中不需要有一个条目。IIRC,该表的两个“边”必须包含有效的候选键。
因此,在业务模型确实需要该选项的情况下,已经实现了 1-1 关系,并且 FK 中的当前非空条目。现在我只需要为业务模型不需要可选部分的情况实现一个方法,以允许 0-1 关系,用于FK 中的当前空条目,同时不允许重复。
感谢您的帮助
请求_
现在包含第三个示例。
以下小节包含使用命令从 Apache OpenOffice Base 导出的半 SQL 导出SCRIPT 'PATH\TO\NAME.sql'
。原始文件及其导出和非导出查询位于如何使用可选 FK 创建索引?示例 3。
我想要3 列/属性 ID_to_part1、model_number 和 ID_to_part2的唯一键;但是,在上一节中,原始问题显示 HSQLDB 版本 1.8.0.10 不允许在作为唯一键一部分的列中包含空值。
HSQLDB 导出
产生某种 SQL ;包括非标准陈述。
SET DATABASE COLLATION "Latin1_General"
CREATE SCHEMA PUBLIC AUTHORIZATION DBA
CREATE CACHED TABLE "Table1"("ID" INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,"ID_to_part1" INTEGER NOT NULL,"model_number" VARCHAR_IGNORECASE(3) NOT NULL,"ID_to_part2" INTEGER)
CREATE CACHED TABLE "Table2"("ID" INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,"content" VARCHAR_IGNORECASE(1) NOT NULL)
CREATE CACHED TABLE "Table3"("ID" INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,"content" VARCHAR_IGNORECASE(1) NOT NULL)
ALTER TABLE "Table1" ADD CONSTRAINT SYS_FK_87 FOREIGN KEY("ID_to_part1") REFERENCES "Table3"("ID") ON DELETE CASCADE ON UPDATE CASCADE
ALTER TABLE "Table1" ADD CONSTRAINT SYS_FK_90 FOREIGN KEY("ID_to_part2") REFERENCES "Table2"("ID") ON DELETE SET NULL ON UPDATE CASCADE
ALTER TABLE "Table1" ALTER COLUMN "ID" RESTART WITH 15
ALTER TABLE "Table2" ALTER COLUMN "ID" RESTART WITH 2
ALTER TABLE "Table3" ALTER COLUMN "ID" RESTART WITH 4
CREATE USER SA PASSWORD ""
GRANT DBA TO SA
SET WRITE_DELAY 0 MILLIS
SET SCHEMA PUBLIC
INSERT INTO "Table1" VALUES(0,0,'123',0)
INSERT INTO "Table1" VALUES(1,1,'456',NULL)
INSERT INTO "Table1" VALUES(2,2,'789',0)
INSERT INTO "Table1" VALUES(3,0,'012',1)
INSERT INTO "Table1" VALUES(6,3,'345',NULL)
INSERT INTO "Table1" VALUES(7,1,'678',1)
INSERT INTO "Table1" VALUES(8,0,'123',NULL)
INSERT INTO "Table1" VALUES(9,0,'123',1)
INSERT INTO "Table1" VALUES(10,1,'456',0)
INSERT INTO "Table1" VALUES(11,1,'456',1)
INSERT INTO "Table1" VALUES(12,1,'456',0)
INSERT INTO "Table1" VALUES(13,1,'123',NULL)
INSERT INTO "Table1" VALUES(14,1,'123',0)
INSERT INTO "Table2" VALUES(0,'B')
INSERT INTO "Table2" VALUES(1,'E')
INSERT INTO "Table3" VALUES(0,'A')
INSERT INTO "Table3" VALUES(1,'C')
INSERT INTO "Table3" VALUES(2,'D')
INSERT INTO "Table3" VALUES(3,'F')
似乎没有导出查询,这里是他们的结果
查询1
加入主表:
SELECT "Table1"."ID", "Table3"."content" AS "Table3_content", "Table1"."model_number", "Table2"."content" AS "Table2_content"
FROM "Table1"
LEFT OUTER JOIN "Table2" ON "Table1"."ID_to_part2" = "Table2"."ID"
LEFT OUTER JOIN "Table3" ON "Table1"."ID_to_part1" = "Table3"."ID"
ORDER BY "ID" ASC
导致:
ID Table3_content model_number Table2_content
0 A 123 B
1 C 456
2 D 789 B
3 A 012 E
6 F 345
7 C 678 E
8 A 123
9 A 123 E
10 C 456 B
11 C 456 E
12 C 456 B
13 C 123
14 C 123 B
查询2
如果第3部分也匹配,则唯一索引的第一部分可以“破坏”所需唯一索引的行/元组。换句话说,其他行不构成威胁(Query1 减去 Query2)。
SELECT *
FROM "Table1"
-- It seem HSQLDB won't support tuples as in WHERE (col1, col2) IN ( SELECT col1, col2 FROM
WHERE "ID_to_part1" IN (
SELECT "ID_to_part1"
FROM "Table1"
GROUP BY "ID_to_part1", "model_number"
HAVING COUNT(*) > 1
) AND "model_number" IN (
SELECT "model_number"
FROM "Table1"
GROUP BY "ID_to_part1", "model_number"
HAVING COUNT(*) > 1
)
ORDER BY "ID_to_part1" ASC, "model_number" ASC, "ID_to_part2" ASC, "ID" ASC
导致:
ID ID_to_part1 model_number ID_to_part2
8 0 123
0 0 123 0
9 0 123 1
13 1 123
14 1 123 0
1 1 456
10 1 456 0
12 1 456 0
11 1 456 1
查询3
将“破坏”所需唯一索引的行/元组。
SELECT "Table1".*
FROM "Table1"
JOIN (
SELECT "ID_to_part1", "model_number", "ID_to_part2"
FROM "Table1"
GROUP BY "ID_to_part1", "model_number", "ID_to_part2"
HAVING COUNT(*) > 1
) AS "non_unique_model"
ON "Table1"."ID_to_part1"="non_unique_model"."ID_to_part1"
AND "Table1"."model_number"="non_unique_model"."model_number"
AND "Table1"."ID_to_part2"="non_unique_model"."ID_to_part2"
ORDER BY "ID_to_part1" ASC, "model_number" ASC, "ID_to_part2" ASC, "ID" ASC
导致:
ID ID_to_part1 model_number ID_to_part2
10 1 456 0
12 1 456 0
美化重要表架构
CREATE CACHED TABLE "Table1"(
"ID" INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
"ID_to_part1" INTEGER NOT NULL,
"model_number" VARCHAR_IGNORECASE(3) NOT NULL,
"ID_to_part2" INTEGER
)
CREATE CACHED TABLE "Table2"(
"ID" INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
"content" VARCHAR_IGNORECASE(1) NOT NULL
)