你好我的表看起来像这样:
CREATE TABLE my_eav(
id INTEGER PRIMARY KEY AUTOINCREMENT,
k TEXT NOT NULL,
v TEXT,
v_link INTEGER,
UNIQUE(k, v) ON CONFLICT REPLACE,
FOREIGN KEY(v_link) REFERENCES posts(id) ON UPDATE ???
);
v_link是另一个表的id列," posts"。当它不为空时," v"列应该采用"标题"的值来自"帖子"。
的专栏当引用的帖子记录更新时,我想更改" v"此表格中的列标题为"标题"帖子表的列。这可能吗?
像
这样的东西... ON UPDATE SET v = posts.title
但当然这不起作用:(
我做了这个触发器:
CREATE TRIGGER my_trigger
AFTER INSERT ON my_eav
WHEN v_link IS NOT NULL
BEGIN
UPDATE my_eav SET v = (SELECT title
FROM posts
WHERE id = v_link);
END;
但我不知道它是否正确
答案 0 :(得分:3)
根据您的说法,听起来这是主要目标:
使 my_eav 表格中的 v 列保持同步 帖子表中的标题列。
如果这是正确的,我首先想到的是你可以通过仅在posts
中存储标题来规范化数据库,如果你需要标题,只需在查询my_eav
时检索它。加入:
select * from my_eav inner join posts on my_eav.v_link = posts.id
where my_ev.id = <my desired record>
但是,它确实可以使用触发器实现。
您没有包含posts
表格设计,但听起来像是这样的:
CREATE TABLE posts(id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT);
所以让我们在那里插入几个样本记录:
insert into posts (title) values('Romeo & Juliet');
insert into posts (title) values('Hamlet');
这给了我们这样一个表格:
--------------------
|id |title |
--------------------
| 1 |Romeo & Juliet |
| 2 |Hamlet |
--------------------
现在让我们用外键创建my_eav
表(我现在省略了唯一约束,所以我们可以专注于触发器)。
CREATE TABLE my_eav(id INTEGER PRIMARY KEY AUTOINCREMENT, k TEXT NOT NULL, v TEXT,
v_link INTEGER, FOREIGN KEY(v_link) REFERENCES posts(id));
所以现在空白的my_eav
表看起来像这样:
-------------------
|id|k |v |v_link |
-------------------
-------------------
让我们测试外键以验证它是否允许my_eav
中的记录,除非它们存在于posts
中(使用我的sqlite实例我必须使用pragma命令强制sqlite兑换外键):
pragma foreign_keys=on;
insert into my_eav(k, v_link) values('test', 3);
Error: FOREIGN KEY constraint failed
这样做很好,如果my_eav
中没有记录,我们就无法在posts
中插入记录。
为了保持两个表之间的标题同步,我们需要两个触发器,而不仅仅是一个:首次创建记录时my_eav
上的触发器,当标题在那里更改时,posts
上的触发器。
首先插入记录时my_eav
触发标题的触发器:
CREATE TRIGGER get_title AFTER INSERT ON my_eav
BEGIN
UPDATE my_eav SET v = (select title from posts where posts.id = v_link);
END;
如果我们通过添加记录来测试它:
insert into my_eav(k, v_link) values('test1', 1);
它抓住了它应该的标题:
-------------------------------
|id|k |v |v_link|
-------------------------------
|1 |test1|Romeo & Juliet|1 |
-------------------------------
另一个记录:
insert into my_eav(k, v_link) values('test2', 1);
现在表:
-------------------------------
|id|k |v |v_link|
-------------------------------
|1 |test1|Romeo & Juliet|1 |
|2 |test2|Romeo & Juliet|1 |
-------------------------------
还有一个:
insert into my_eav(k, v_link) values('test3', 2);
现在表:
-------------------------------
|id|k |v |v_link|
-------------------------------
|1 |test1|Romeo & Juliet|1 |
|2 |test2|Romeo & Juliet|1 |
|3 |test3|Hamlet |2 |
-------------------------------
现在,这是我们需要创建的第二个触发器,在my_eav
发生更改时会保持posts
更新。 请注意,我们会在posts
表格上创建此触发器。在您的示例代码中,您似乎试图拉更改后的值posts
使用my_eav
上的触发器,实际上您需要使用my_eav
上的触发器将更改后的值推送到posts
:
CREATE TRIGGER update_title AFTER UPDATE ON posts
BEGIN
UPDATE my_eav SET v = (select title from posts where posts.id = v_link);
END;
现在让我们通过更新posts
表中的标题来测试它:
update posts set title='Othello' where title='Romeo & Juliet';
检查更新是否发生:
select * from posts;
表现在显示:
--------------------
|id |title |
--------------------
| 1 |Othello |
| 2 |Hamlet |
--------------------
如果我们检查my_eav
,
select * from my_eav;
posts
上的触发器使其保持同步:
-------------------------------
|id|k |v |v_link|
-------------------------------
|1 |test1|Othello |1 |
|2 |test2|Othello |1 |
|3 |test3|Hamlet |2 |
-------------------------------
希望我理解这个问题,这有帮助。
答案 1 :(得分:3)
最佳解决方案是使用如上所述的连接。
select * from my_eav
left join posts on my_eav.v_link = posts.id
但是,如果你想要触发器,你就会得到它们。 ;)
您可以使用“SQLite(WebSQL)”选项在http://sqlfiddle.com/上测试下面的所有代码
你必须选择查询终止符 - 管道[/]
CREATE TABLE posts(id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT)/
CREATE TABLE my_eav(
id INTEGER PRIMARY KEY AUTOINCREMENT,
k TEXT NOT NULL,
v TEXT,
v_link INTEGER,
UNIQUE(k, v) ON CONFLICT REPLACE,
FOREIGN KEY(v_link) REFERENCES posts(id)
)/
CREATE TRIGGER my_trigger_ins
AFTER INSERT ON my_eav
BEGIN
UPDATE my_eav SET v = (SELECT title FROM posts WHERE id = NEW.v_link) where id = NEW.id;
END/
CREATE TRIGGER my_trigger_upd
AFTER UPDATE ON my_eav
WHEN (OLD.v_link <> NEW.v_link) or (OLD.v_link is not null and NEW.v_link is null)
or (NEW.v_link is not null and OLD.v_link is null)
BEGIN
UPDATE my_eav SET v = (SELECT title FROM posts WHERE id = NEW.v_link) where id = OLD.id;
END/
CREATE TRIGGER my_trigger_b_ins BEFORE INSERT ON my_eav
WHEN NEW.v is not null and NEW.v <> (SELECT title FROM posts WHERE id = NEW.v_link)
BEGIN
SELECT RAISE(ABORT,'V must be from posts.');
END/
CREATE TRIGGER my_trigger_b_upd BEFORE UPDATE ON my_eav
WHEN NEW.v is not null and NEW.v <> (SELECT title FROM posts WHERE id = NEW.v_link)
BEGIN
SELECT RAISE(ABORT,'V must be from posts.');
END/
CREATE TRIGGER update_posts_title UPDATE OF title ON posts
BEGIN
UPDATE my_eav SET v = new.title WHERE v_link = old.id;
END/
这里有一些测试。让我们用一些数据填充表格。
insert into posts (title) values('Romeo')/
insert into posts (title) values('Hamlet')/
insert into my_eav(k, v_link) values('test1', 1)/
insert into my_eav(k, v_link) values('test2', 2)/
insert into my_eav(k) values('test3')/
检查my_trigger_ins - 确定
select * from my_eav
id k v v_link
1 test1 Romeo 1
2 test2 Hamlet 2
3 test3 (null) (null)
检查update_posts_title - 确定
update posts set title = 'Romeo1' where id = 1
select * from my_ea
id k v v_link
1 test1 Romeo1 1
2 test2 Hamlet 2
3 test3 (null) (null)
检查my_trigger_upd - 确定
update my_eav set k = 'test11' where id = 1
select * from my_ea
id k v v_link
1 test11 Romeo 1
2 test2 Hamlet 2
3 test3 (null) (null)
检查my_trigger_b_ins - 确定
insert into my_eav(k, v, v_link) values('test1rrrr', 'rrrrr', 2)
Result: could not execute statement due to a constaint failure (V must be from posts.) - OK
检查my_trigger_b_upd - 确定
update my_eav set v = 'xxxx' where id = 1
Result: could not execute statement due to a constaint failure (V must be from posts.) - OK
多数民众赞成。真的使用left join posts
。