Sql 如何处理相互递归插入
我有一个定义相互递归表的模型:Sql 如何处理相互递归插入,sql,postgresql,database-design,foreign-keys,referential-integrity,Sql,Postgresql,Database Design,Foreign Keys,Referential Integrity,我有一个定义相互递归表的模型: Answer questionId QuestionId text Question text correct AnswerId 我需要做什么才能真正插入问题?我首先要知道正确答案是什么。但要插入答案,我需要知道它回答了什么问题 如果有关系的话,我是博士后 DDL是: CREATE TABLE answer ( id integer NOT NULL, -- answer id text character
Answer
questionId QuestionId
text
Question
text
correct AnswerId
我需要做什么才能真正插入问题?我首先要知道正确答案是什么。但要插入答案,我需要知道它回答了什么问题
如果有关系的话,我是博士后
DDL是:
CREATE TABLE answer (
id integer NOT NULL, -- answer id
text character varying NOT NULL, -- answer text
question_id bigint NOT NULL -- question id
);
CREATE TABLE question (
id integer NOT NULL, -- question id
question character varying NOT NULL, -- question text
correct bigint NOT NULL, -- correct answer
solution character varying NOT NULL -- solution text
);
ALTER TABLE ONLY answer ALTER COLUMN id SET DEFAULT nextval('answer_id_seq'::regclass);
ALTER TABLE ONLY answer
ADD CONSTRAINT answer_question_id_fkey FOREIGN KEY (question_id) REFERENCES question(id);
ALTER TABLE ONLY question ALTER COLUMN id SET DEFAULT nextval('question_id_seq'::regclass);
ALTER TABLE ONLY question
ADD CONSTRAINT question_correct_fkey FOREIGN KEY (correct) REFERENCES answer(id);
我会用一个空的正确答案插入问题。然后我将插入到答案中,最后我将更新问题并设置正确的答案ID。我在看到DDL后四处查看。请考虑调用一个函数,用正确的答案插入一个问题,并给一个给定的问题加上(错误的)答案。第一个函数的结构允许应用程序提取questionID的匿名返回记录,并将其用于第二个函数的后续调用,以添加错误答案
CREATE FUNCTION newQuestion (questionText varchar, questionSolutionText varchar, answerText varchar, OUT questionID integer) AS $$
BEGIN
START TRANSACTION;
SET CONSTRAINTS question_correct_fkey DEFERRED;
questionID := nextval('question_id_seq');
answerID := nextval('answer_id_seq');
INSERT INTO question (id, question, correct, solution) values (questionID, questionText, answerID, questionSolutionText);
INSERT INTO answer (id, text, question_id) values (answerID, answerText, questionID);
SET CONSTRAINTS question_correct_fkey IMMEDIATE;
COMMIT TRANSACTION;
END;
$$
CREATE FUNCTION addFalseAnswer (questionID integer, answerText varchar) AS $$
BEGIN
INSERT INTO answer (text, question_id) VALUES (answerText, questionID);
END;
$$
我已经很久没有为PostGreSQL编写SQL了,所以我希望这里一切正常。如果有任何问题,请告诉我。如果您在带有的单个语句中输入问题和答案,您甚至不需要可延迟的FK约束。更不用说实际制作(或设置)它们
延迟
——这将要昂贵得多
数据模型
首先,我清理了您的数据模型:
创建表格问题(
问题\u id串行主键
,正确答案id int不为空
,问题文本不为空
,解决方案文本不为空
);
创建表格答案(
应答id串行主键
,问题_idint非空引用问题
,答案文本不为空
);
更改表格问题添加约束问题\u更正\u答案\u id\u fkey
外键(正确答案id)引用答案(答案id);
- 不要使用非描述性的“id”或“text”(也是基本类型名称)作为列名
- 为了节省空间,将整数列放在第一位。见:
是不必要的,bigint
应该足够了integer
- 使用简化模式定义
- 定义主键。PK列自动为
非空
serial
列)之后,我们可以使用INSERT
语句的RETURNING
子句获得自动生成的ID。但是在这种特殊情况下,每个插入都需要两个ID,因此我使用nextval()
获取其中一个ID以使其运行
,其中q为(
提出疑问
(正确答案、问题、解决方案)
值(nextval('answer\u answer\u id\u seq')、'How?'、'DEFERRABLE FK&CTE')
返回正确的答案id、问题id
)
在答案中插入
(答案、问题、答案)
选择正确的答案id、问题id,“使用可延迟的FK&CTE”
来自q;
我知道序列的名称('answer\u answer\u id\u seq'
),因为我查过了。这是默认名称。如果您不知道,请使用安全表格:
可延期
或延期
约束?
IMMEDIATE
约束在每条语句的末尾进行检查
我的解决方案是一句话。这就是为什么它在两个单独的语句在一个事务中失败或失败的情况下工作。您需要设置约束。。。推迟代码>喜欢和。
但是,请注意以下段落中的免责声明:
未声明的唯一性和排除约束
可延迟的
也会立即检查
因此UNIQUE
和EXCLUDE
需要可延迟
,才能使CTE为它们工作。这包括主键
约束:
非延迟唯一性约束
当唯一
或主键
约束不可延迟时,PostgreSQL
在插入或删除行时立即检查唯一性
被改进的。SQL标准规定应该强制执行唯一性
仅在声明末尾;这会在以下情况下产生影响:
例如,单个命令更新多个键值。取得
标准兼容行为,将约束声明为可延迟
不延迟(即,最初立即
)。请注意,这可能是错误的
明显慢于立即唯一性检查
我们在相关问题下对此进行了详细讨论:
我感觉不到这里的递归。这看起来像是一种直接的外键关系,除非在处理问题时。问题ID 1的回答ID为2,而回答ID则不是1?@Jaaz:这是多项选择题测试的模型。比如说,每个问题都有4个答案。其中只有一个是正确的。问题知道哪一个是正确的,答案也知道他们所指的问题。我不能插入问题,除非我知道它的答案id是什么。我不能插入答案,除非我知道它的问题id是什么。哈哈,这看起来太傻了。你不能在不知道正确答案的情况下插入问题,也不能在不知道问题的情况下插入答案?你能重新设计这个愚蠢的东西吗,或者你被它卡住了?正确答案不应该存储在问题记录中…@12th:它们不是相互冲突的要求。问题在于,数据库无法“同时”(在单个插入的上下文中)插入两个需求。至少据我所知。因此,我提出了一个问题。我终于记住了要搜索的正确术语:“循环引用”是这种情况的常用名称。这就引出了一个问题:不确定是否有任何答案会直接在Postgres上运行,但原则和技术应该适用。这里的并发或回滚没有问题,因为nextval()不会在两次
nextval(pg_get_serial_sequence('answer', 'answer_id'))