将列的值更改为外部列的值
Change value of column to a value from a foreign column
你好,我的 table 看起来像这样:
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是另一个table、"posts"的id列。当它不为空时,"v" 列应从 "posts".
中获取 "title" 列的值
当引用的 post 记录更新时,我想将此 table 上的 "v" 列更改为 [=34] 的 "title" 列=]s table。这可能吗?
类似
... 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;
但是不知道对不对
根据你所说的,这听起来像是主要目标:
Keep the v column in the my_eav table synchronized with
the title column in the posts table.
如果这是正确的,我的第一个想法是您可以通过仅将标题存储在 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
table 设计,但听起来是这样的:
CREATE TABLE posts(id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT);
所以让我们在其中插入一些示例记录:
insert into posts (title) values('Romeo & Juliet');
insert into posts (title) values('Hamlet');
这给了我们这样的 table:
--------------------
|id |title |
--------------------
| 1 |Romeo & Juliet |
| 2 |Hamlet |
--------------------
现在让我们用外键创建 my_eav
table(我暂时省略了唯一约束,所以我们可以专注于触发器)。
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
table 看起来像这样:
-------------------
|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
很好,如果 posts
中不存在记录,我们无法将记录插入 my_eav
。
为了使标题在两个 table 之间保持同步,我们将需要 两个 触发器,而不仅仅是一个:[=31= 上的触发器] 首次创建记录时触发,并在 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);
Table现在:
-------------------------------
|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);
Table现在:
-------------------------------
|id|k |v |v_link|
-------------------------------
|1 |test1|Romeo & Juliet|1 |
|2 |test2|Romeo & Juliet|1 |
|3 |test3|Hamlet |2 |
-------------------------------
现在,这是我们需要创建的第二个触发器,它将在 posts
发生变化时保持 my_eav
更新。 请注意,我们正在 posts
table 上创建此触发器。 在您的示例代码中,看起来您正试图 拉 使用 my_eav
上的触发器从 posts
更改的值,而实际上您需要 将更改的值 推送到 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
table:
中的标题来测试它
update posts set title='Othello' where title='Romeo & Juliet';
检查更新是否发生:
select * from posts;
Table 现在显示:
--------------------
|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 |
-------------------------------
希望我对问题的理解是正确的,这对您有所帮助。
最好的解决方案是如上所述使用连接。
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
真的。
你好,我的 table 看起来像这样:
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是另一个table、"posts"的id列。当它不为空时,"v" 列应从 "posts".
中获取 "title" 列的值当引用的 post 记录更新时,我想将此 table 上的 "v" 列更改为 [=34] 的 "title" 列=]s table。这可能吗?
类似
... 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;
但是不知道对不对
根据你所说的,这听起来像是主要目标:
Keep the v column in the my_eav table synchronized with the title column in the posts table.
如果这是正确的,我的第一个想法是您可以通过仅将标题存储在 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
table 设计,但听起来是这样的:
CREATE TABLE posts(id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT);
所以让我们在其中插入一些示例记录:
insert into posts (title) values('Romeo & Juliet');
insert into posts (title) values('Hamlet');
这给了我们这样的 table:
--------------------
|id |title |
--------------------
| 1 |Romeo & Juliet |
| 2 |Hamlet |
--------------------
现在让我们用外键创建 my_eav
table(我暂时省略了唯一约束,所以我们可以专注于触发器)。
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
table 看起来像这样:
-------------------
|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
很好,如果 posts
中不存在记录,我们无法将记录插入 my_eav
。
为了使标题在两个 table 之间保持同步,我们将需要 两个 触发器,而不仅仅是一个:[=31= 上的触发器] 首次创建记录时触发,并在 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);
Table现在:
-------------------------------
|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);
Table现在:
-------------------------------
|id|k |v |v_link|
-------------------------------
|1 |test1|Romeo & Juliet|1 |
|2 |test2|Romeo & Juliet|1 |
|3 |test3|Hamlet |2 |
-------------------------------
现在,这是我们需要创建的第二个触发器,它将在 posts
发生变化时保持 my_eav
更新。 请注意,我们正在 posts
table 上创建此触发器。 在您的示例代码中,看起来您正试图 拉 使用 my_eav
上的触发器从 posts
更改的值,而实际上您需要 将更改的值 推送到 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
table:
update posts set title='Othello' where title='Romeo & Juliet';
检查更新是否发生:
select * from posts;
Table 现在显示:
--------------------
|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 |
-------------------------------
希望我对问题的理解是正确的,这对您有所帮助。
最好的解决方案是如上所述使用连接。
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
真的。