用于交叉链接表和外键使用的Sqlite设计

用于交叉链接表和外键使用的Sqlite设计,sql,database,sqlite,Sql,Database,Sqlite,我不知道这是不是该问的地方。因为这是一个关于sql数据库设计的问题,我一直在考虑数据库管理员,但因为该网站的目标是数据库专业人士(我绝对不是专业人士),所以我将在这里发布我的问题。如果你认为这类问题有更好的答案,请给我指出正确的答案 开始提问。 我正在设计一个文学作品翻译数据库。因为这涉及到人,而且人通常不适合“静态”数据模型,所以我有一个非常复杂的模式。这里只是其中的一部分,关于人们的名字。因为涉及到外国作者(特别是日本人),我还有一个问题,就是人名的音译。目前,人员和姓名数据库的结构如下

我不知道这是不是该问的地方。因为这是一个关于sql数据库设计的问题,我一直在考虑数据库管理员,但因为该网站的目标是数据库专业人士(我绝对不是专业人士),所以我将在这里发布我的问题。如果你认为这类问题有更好的答案,请给我指出正确的答案

开始提问。

我正在设计一个文学作品翻译数据库。因为这涉及到人,而且人通常不适合“静态”数据模型,所以我有一个非常复杂的模式。这里只是其中的一部分,关于人们的名字。因为涉及到外国作者(特别是日本人),我还有一个问题,就是人名的音译。目前,人员和姓名数据库的结构如下

让我们举一个例子:

我有一个人叫“Kyokutei Bakin”,音译为曲亭馬琴 表意文字和キョクテイ バキン 用日语拼音字母。这位作者也被称为“Takizawa Bakin”(滝沢馬琴, タキザワ バキン) 等等

具有一对多关系的3表结构说明了一个人有多个名字(传记名、笔名、ecc…),并且每个名字都可以有多个语音读物

这一切都很好。当我搜索某人时,我只是离开了连接表并为各个字段添加OR条件。例如:

SELECT DISTINCT name.name_text, phonetic_name.name_text FROM name
LEFT JOIN phonetic_name ON (name.name_id=phonetic_name.name_id)
WHERE (name.name_text LIKE "%bak%")
OR (phonetic_name.name_text LIKE "%馬琴%");
我的问题是,我希望其中一个名字成为那个人的主名。我这样做的方式是在“person”表中添加一个“main\u name”列,指向“name”表的“name\u id”列。这样,当我只需要主名时,我就可以
在(person.main\u name=name.name\u id)
上连接名字

我的疑问是:

-将两个表交叉链接是一种好做法吗

(此处“姓名”在person_id上引用“person”,但同时“person”在main_姓名中引用“name”)

-这会引起问题吗

-在这种情况下,如何设置外键

-如果这太混乱了,我该如何改进设计

其他信息:
作为一个设计问题,sql实现不应该如此重要,但为了以防万一,我正在使用sqlite3。

我个人会这样简化设计:

Select distinct b.person_id, b.name as main_name
From name a
Inner join name b on a.parent_name_id=b.name_id
Where a.name like ‘%...%’
Select distinct b.person_id,
b.name as main_name,
c.name as kanji_name,
d.name as katakana_name
From name a
Inner join name b on a.parent_name_id=b.name_id
Left join name c on b.parent_name_id=c.parent_name_id and c.name_type=‘kanji’
Left join name d on b.parent_name_id=d.parent_name_id and d.name_type=‘katakana’
Etc...
Where a.name like ‘%...%’
表:
person

  • 个人id
    (主键)
表:
name

  • name\u id
    (主键)
  • name
  • name\u type
  • parent\u name\u id
    (自身外键)
  • person\u id
    (person表的外键)
name
具有递归关系,其中
parent\u name\u id
包含人员主要姓名的
name\u id
。请注意,对于主要姓名
name\u id=parent\u name\u id
。在
name\u type
列中,可以存储姓名类型(拼音、表意文字、汉字等)。如果您希望使用纯第三范式,则可以将
name\u type
进一步规范化为专用表

我想说,这种设计的主要好处是,在查询任何类型的名称时,它大大简化了您的查询。您只需运行如下操作:

Select distinct b.person_id, b.name as main_name
From name a
Inner join name b on a.parent_name_id=b.name_id
Where a.name like ‘%...%’
Select distinct b.person_id,
b.name as main_name,
c.name as kanji_name,
d.name as katakana_name
From name a
Inner join name b on a.parent_name_id=b.name_id
Left join name c on b.parent_name_id=c.parent_name_id and c.name_type=‘kanji’
Left join name d on b.parent_name_id=d.parent_name_id and d.name_type=‘katakana’
Etc...
Where a.name like ‘%...%’
此外,您可以为一个人存储任意数量的姓名

如果要从不同类型返回多个名称,可以执行以下操作:

Select distinct b.person_id, b.name as main_name
From name a
Inner join name b on a.parent_name_id=b.name_id
Where a.name like ‘%...%’
Select distinct b.person_id,
b.name as main_name,
c.name as kanji_name,
d.name as katakana_name
From name a
Inner join name b on a.parent_name_id=b.name_id
Left join name c on b.parent_name_id=c.parent_name_id and c.name_type=‘kanji’
Left join name d on b.parent_name_id=d.parent_name_id and d.name_type=‘katakana’
Etc...
Where a.name like ‘%...%’

谢谢你的回答。对主名称的内部引用是一个有趣的解决方案。我想对于大多数备选方案,必须考虑权衡。例如,因为除了字母表之外,我还有“名称类别”(例如:专有名称、笔名、ecc…)对于每个拼音选项,这些结果都将是重复的条目。但在这种情况下,这可能不是什么大问题。此外,我现在有多个表,在main_name上连接,我可以为一个人获得一个单行结果(这对我在搜索时返回数据很有用,而无需对其进行后期处理,比如在php中)。但我看不到用你提议的结构来做这件事的方法。我很确定这是可以做到的,只是我不知道怎么做。@HirabayashiTaro你可以选择一个不同的人名和主名来做一个记录。我已经更新了我的答案。@HirabayashiTaro关于名字的类别,一个名字能属于几个类别吗?我是的,这意味着名称和类别之间存在多对多关系。我建议您将此信息存储到专用的连接表中。例如:名称\u类别(命名\u id,类别\u id),然后您有一个专用的表类别(类别\u id,类别\u名称…)就我所能想到的,一个名字应该属于一个类别,所以一对多的关系就足够了。关于为每个人返回一行(我认为返回行是“person\u id,name\u latin,name\u in_kanji,name\u in_katakana”)我在stack上搜索过它,我认为将各种名称与GROUP_CONCAT连接起来应该可以做到这一点。但我对sql不太熟悉,所以我需要一些时间来了解它。