English 中文(简体)
向与另一个表相关的表中插入行。
原标题:
  • 时间:2008-12-08 19:42:59
  •  标签:

在我的数据库模式中,我有一个被标识的实体。标识符可以被重用,因此与实体之间存在一对多的关系。例如:一个人可以有一个绰号。昵称不是唯一的,可以在许多人之间共享。因此,模式可能如下所示:

PERSON
id
name
nickname_id

NICKNAME
id
name

问题是,在插入新人员时,我必须首先查询NICKNAME以查看昵称是否存在。如果不存在,则必须在NICKNAME中创建一行。在插入许多人员时,这可能会很慢,因为每个人员插入都会导致对NICKNAME的查询。

我可以通过先为所有昵称查询昵称来优化大型插入。JPA查询语言:

SELECT n FROM NICKNAME n WHERE name in ( Krusty ,  Doppy ,  Flash , etc)

然后根据需要创建新的昵称,接着将昵称 ID 设置到人员上。

这会使软件变得有些复杂,因为它必须在内存中暂时存储昵称。此外,一些数据库对IN子句的参数有限制(例如SQL Server为2100),因此我必须执行多个查询。

我很好奇其他人如何处理这个问题。更具体地说,当一个数据库被规范化并且一个实体有与另一个实体的关系时,插入一个新实体基本上会导致必须检查另一个实体。对于大型插入,除非将操作提升到代码域中,否则这可能会很慢。是否有一种自动插入相关表行的方式? 我很好奇其他人如何处理这个问题。更具体地说,当一个数据库被规范化并且一个实体有与另一个实体的关系时,插入一个新实体基本上会导致必须检查另一个实体。对于大型插入,除非将操作提升到代码域中,否则这可能会很慢。是否有一种自动插入相关表行的方式?

FYI,我正在使用Hibernate对JPA的实现

问题回答

我不确定ORM能否处理这个问题,但在纯SQL中,你可以:

  1. Create a table of name/nickname pairs,
  2. INSERT INTO NicknameTable SELECT Nickname FROM temp WHERE Nickname NOT IN (SELECT Nickname FROM NicknameTable)
  3. Insert into main table knowing the Nickname exists.

在您的例子中,您可以仅使用一个可为NULL的昵称列,而无需另一个表格,除非一个人可以有多个昵称。

真相是?我会把昵称作为Person表中的一个varchar列,然后忘记昵称表。昵称是一个人的属性,而不是一个独立的实体。

这是一个简化的例子吗?你的标识符确实从实体关系中获益吗?

编辑:好的,我明白这只是一个人为的例子。这个问题很好,因为它出现得相当频繁。

标准的 SQL 支持一种带有可选“...ON DUPLICATE KEY UPDATE...”子句的 INSERT 语句形式。对该语法的支持因数据库品牌而异。如果在昵称表中的标识符名称中添加一个UNIQUE 约束,重复的条目将调用子句的UPDATE 部分(您可以进行虚拟更新,而不是更改任何内容)。

CREATE TABLE Nickname (
  id SERIAL PRIMARY KEY,
  name VARCHAR(20) UNIQUE
);

INSERT INTO Nickname (name) VALUES ("Bill")
  ON DUPLICATE KEY UPDATE name = name;
INSERT INTO Person(Name, NicknameID)
    VALUES(:name, (SELECT id FROM Nickname WHERE Name = :nickname))

如果插入失败是因为昵称不存在,则先插入昵称,然后再插入个人记录。

我假设::name 和 :nickname 是标识主机变量,包含用户的姓名和昵称 - 并且如果在SQL中省略了 person.id 列,它将自动被赋值。请根据您的情况进行调整。

如果你认为大部分昵称都是独一无二的,那么你可以尝试无条件地插入这个昵称,但如果该昵称已存在,就忽略出现的错误。

另外,也许 MERGE 语句可以帮助?它提供了插入新值或更新现有值的选项。语法和支持因数据库而异,但可能比 ON DUPLICATE 选项更常见。





相关问题
热门标签