我在 WHERE 条件下尝试了 INSERT。现在, WHERE 将取决于每个新插入的记录,例如
WHERE NOT EXISTS (select ... from <table I am inserting records into>)
.
但是,WHERE 子句被评估一次,并且不考虑每个新插入的记录。
我知道 INSERT OR IGNORE,或 INSERT OR UPDATE 或 UPSERT ... 然而,在我的例子中,WHERE 子句会比仅仅验证密钥的存在更复杂。
问题是查询优化器永远只评估一次WHERE,而不是一条一条地考虑新插入的记录。很公平。
问题:有没有办法强制查询优化器在插入后立即考虑每条记录?
作为一个(有点理论性的)例子:从递归生成的数列中引入质数,WHERE 条件声明它不能被表中已经存在的任何(质数)数相除。密码 WON'T work;它将一共介绍19个数字。
CREATE TABLE pnumbers (pnumber number primary key);
with r as
(select 2 as n union all select n+1 as n from r where n < 20)
insert into pnumbers
select n from r where not exists
(select pnumber from pnumbers pn where r.n % pn.pnumber = 0 );
附言 相反, DELETE .. WHERE 工作完美 并且速度非常快。下面的代码在我的游戏笔记本电脑上仅用 90 秒就消除了 1000 万个连续数字中的非素数——(然而,这不是我的想法):
delete from pnumbers where exists (select pnumber from pnumbers pn2
where pn2.pnumber <= sqrt(pnumbers.pnumber) and pnumbers.pnumber % pn2.pnumber = 0);
问题是查询优化器评估了一次 WHERE 永远
不,这不是真的。
WHERE
子句对 r
的每一行求值一次,因为 EXISTS
的子查询是一个 correlated 子查询。问题有点不一样
在任何
INSERT INTO ... SELECT...
语句中,首先执行SELECT...
语句,完成后返回的结果集被插入到表中。这意味着对于您的理论示例,在该语句返回之前不会插入表
pnumbers
:
with r as
(select 2 as n union all select n+1 as n from r where n < 20)
select n from r where not exists
(select pnumber from pnumbers pn where r.n % pn.pnumber = 0 );
在上面的语句中对表
pnumbers
的任何引用都将访问一个空表,因为尚未插入任何行。r
的所有行。确实在 SQLite 的INSERT 的文档中没有清楚地概述这种行为,但这是意思:
为每行数据插入一个新条目到表中 通过执行 SELECT 语句返回。