Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/86.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何避免循环引用情况_Sql_Database_Postgresql_Circular Dependency - Fatal编程技术网

Sql 如何避免循环引用情况

Sql 如何避免循环引用情况,sql,database,postgresql,circular-dependency,Sql,Database,Postgresql,Circular Dependency,关于SQL表、循环引用和外键的建议 我对SQL非常陌生(大约一个月左右),所以请原谅我后来的任何不幸幼稚。 我正在做一个关于故事的项目,其中一个用户可以开始一个故事,另一个用户可以添加到该故事中。 目前,我的两个主要表格是故事和段落。 故事由段落组成。段落只是一段文字。 故事模式如下所示: stid varchar not null primary key, title text not null, description text, created_at timestamptz DEFAULT

关于SQL表、循环引用和外键的建议

我对SQL非常陌生(大约一个月左右),所以请原谅我后来的任何不幸幼稚。 我正在做一个关于故事的项目,其中一个用户可以开始一个故事,另一个用户可以添加到该故事中。 目前,我的两个主要表格是故事和段落。 故事由段落组成。段落只是一段文字。 故事模式如下所示:

stid varchar not null primary key,
title text not null,
description text,
created_at timestamptz DEFAULT now()
prid bigint not null primary key,
story varchar not null REFERENCES stories(stid),
maintext text,
writer text not null REFERENCES users(username),
parentpr bigint, //the previous paragraph
childpr bigint, //the next paragraph
created_at timestamptz DEFAULT now()
CREATE TABLE paragraph (
    paragraph_id SERIAL PRIMARY KEY,
    story_id INTEGER NOT NULL REFERENCES stories (story_id),
    position INTEGER NOT NULL,
    -- Other columns
    created_at TIMESTAMPTZ DEFAULT now()
)
段落模式如下所示:

stid varchar not null primary key,
title text not null,
description text,
created_at timestamptz DEFAULT now()
prid bigint not null primary key,
story varchar not null REFERENCES stories(stid),
maintext text,
writer text not null REFERENCES users(username),
parentpr bigint, //the previous paragraph
childpr bigint, //the next paragraph
created_at timestamptz DEFAULT now()
CREATE TABLE paragraph (
    paragraph_id SERIAL PRIMARY KEY,
    story_id INTEGER NOT NULL REFERENCES stories (story_id),
    position INTEGER NOT NULL,
    -- Other columns
    created_at TIMESTAMPTZ DEFAULT now()
)
我正在考虑在故事模式中添加一个headpara和lastpara列(使用ALTER),这样我就可以轻松访问第一段和最后一段,但这会造成循环引用的情况,因为故事将引用段落,反之亦然。这样行吗?当我开始处理大量的数据和查询时,它会变得更加复杂吗

我想到了一个解决方案,其中我有另一个表: 故事段落分配。模式:

ID primary key
story REFERENCES stories(stid),
headpara REFERENCES paragraph(prid),
lastpara REFERENCES paragraph(prid)
出于某种原因,我不相信这种解决办法。我觉得这是多余的。这不是一个多对多的情况。但是段落需要引用故事,我需要能够访问故事的第一段和最后一段

另一种可能的解决方案是在段落模式中有两个布尔列,称为head和tail,这样第一个段落就可以用

WHERE story == stID AND head == True. 

想法?当我的段落表非常大时,这个解决方案似乎会成为一个问题。非常感谢。

您可以用任何一种方法来解决问题。如果你知道头一段和最后一段是非常重要的,那么在故事中引用它们就可以了

在这两种情况下,维护关系完整性都有一点挑战。大概,您希望标题和最后几段在同一个故事中。为此,您需要一个复合键。您需要使用单独的
altertable
语句添加键。因此:

alter table paragraph add constraint unq_paragraph_story_prid unique (story, prid);

alter table stories add constraint fk_stories_headpara
    foreign key (stid, headpara) references paragraph(story, prid);

alter table stories add constraint fk_stories_lastpara
    foreign key (stid, lastpara) references paragraph(story, prid);
类似地,如果使用标志,则需要确保每个类型集只有一个标志。更新时可能会有点痛苦。该约束看起来像:

create unique index unq_paragraph_headpara paragraph(story) where head = 1;

create unique index unq_paragraph_lastpara paragraph(story) where last = 1;
有关命名和其他事项的注释:

  • id
    s应该是数字,如果可以的话。这简化了外键引用
  • id的名称应完整拼写(
    paragraphId
    paragraphId
    )或简单地
    id
    。如果使用
    prid
    ,可能会与另一个表混淆
  • 并非所有数据库都支持筛选的唯一索引。在这些情况下,您需要使用触发器或其他机制

事实上,我不愿意一开始就有一个单独段落的表格

当一个作家编辑他们的作品时,段落对他们来说并不是一种难以划分的单元。当我修改写作时,在段落之间移动句子、重新排列段落、合并段落、分隔段落,甚至删除整个段落都是经常发生的事情。这些类型的更新将很难用您设置的结构实现。这使得您选择的划分有问题,而您面临的问题只是这个结构如何相当不自然的另一个方面

如果您需要支持编辑 如果您需要支持编辑故事,那么我可能倾向于查看非关系数据库(例如,coach或Mongo)

如果我坚持使用PostgreSQL,我可能会先尝试一个包含整个故事的专栏。在PostgreSQL中,SQL最多可以处理大约1GB的文本。这可能够大了。假设每个字符是两个字节(对于使用UTF-8的英语,这是一个高估值),每个单词是10个字符和1个空格(同样是an),则该列可以容纳超过个单词的故事。如果段落包含格式标记,则该数字当然会下降

但这也会遇到其他问题:来回移动大量的文本可能会很慢,并且在更新时维护索引(可能是全文索引)会很昂贵。索引问题可以通过或等技术解决;来回移动大量文本的问题更难解决。但是,如果你要处理的故事相对较小,那么正常的全文机制对你来说就足够了

但底线是,如果故事可以编辑,按段落划分故事会使构建软件变得更加困难,你应该重新思考架构

如果您只支持读取和批量加载 但是,如果编辑不是您需要支持的功能,那么您可以将故事严格地按段落分割,作为一种优化。在本例中,您将批量插入一篇文章的所有段落,从而允许您在导入时将它们拆分为单独的行。“编辑”包括删除所有段落并插入一组新段落

在这种情况下,“链表”结构不再有意义。链表优化对列表的编辑(插入和删除为O(1)),但是如果按段落分解故事是可行的(如我上面所述),那么列表中的编辑就不再需要优化了。相反,您将优化读取。这可能需要某种类型的随机访问。例如,你可以一次读5段,因为用户在故事中滚动,这就要求你可以在中间的任意段落开始阅读。 这表明了一种完全不同且更自然的表格组织方式:在段落表格上放置一列,表示位置。批量插入段落时可以生成此列的值。这使得按位置获取变得微不足道。例如,要在用户滚动时加载下一个段落,只需跟踪为他们获取的最后一个段落的位置(如pa)