【发布时间】:2018-04-23 08:59:01
【问题描述】:
我有以下 SQLite 表
CREATE TABLE keywords
(
id INTEGER PRIMARY KEY,
lang INTEGER NOT NULL,
kwd TEXT NOT NULL,
count INTEGER NOT NULL DEFAULT 0,
locs TEXT NOT NULL DEFAULT '{}'
);
CREATE UNIQUE INDEX kwd ON keywords(lang,kwd);
使用 PHP 我通常需要在此表中插入关键字,或者如果关键字已经存在,则更新行数。举个例子
$langs = array(0,1,2,3,4,5);
$kwds = array('noel,canard,foie gras','','','','','');
我现在这些数据通过下面的代码运行
$len = count($langs);
$klen = count($kwds);
$klen = ($klen < $len)?$klen:$len;
$sqlite = new SQLite3('/path/to/keywords.sqlite');
$iStmt = $sqlite->prepare("INSERT OR IGNORE INTO keywords (lang,kwd)
VALUES(:lang,:kwd)");
$sStmt = $sqlite->prepare("SELECT rowid FROM keywords WHERE lang = :lang
AND kwd = :kwd");
if (!$iStmt || !$sStmt) return;
for($i=0;$i < $klen;$i++)
{
$keywords = $kwds[$i];
if (0 === strlen($keywords)) continue;
$lang = intval($langs[$i]);
$keywords = explode(',',$keywords);
for($j=0;$j < count($keywords);$j++)
{
$keyword = $keywords[$j];
if (0 === strlen($keyword)) continue;
$iStmt->bindValue(':kwd',$keyword,SQLITE3_TEXT);
$iStmt->bindValue(':lang',$lang,SQLITE3_INTEGER);
$sStmt->bindValue(':lang',$lang,SQLITE3_INTEGER);
$sStmt->bindValue(':kwd',$keyword,SQLITE3_TEXT);
trigger_error($keyword);
$iStmt->execute();
$sqlite->exec("UPDATE keywords SET count = count + 1 WHERE lang =
'{$lang}' AND kwd = '{$keyword}';");
$rslt = $sStmt->execute();
trigger_error($sqlite->lastErrorMsg());
trigger_error(json_encode($rslt->fetchArray()));
}
}
生成以下trigger_error 输出
关键字:noel 最后一个错误:不是错误 选择结果:{"0":1,"id":1}
关键字:canard 上一个错误:不是错误
SELECT Reult:false关键字:鹅肝 上一个错误:不是错误 选择结果:假
从 SQLite 命令行中,我看到三个行条目在表中存在且正确,其中 id/rowid 列分别设置为 1、2 和 3。 lastErrorMsg 不报告错误,但三个$rslt->fetchArray() 语句中有两个返回false,而不是具有rowid/id 属性的数组。那么我在这里做错了什么?
我对此进行了更多调查,并找到了潜在的案例。在我的原始代码中,第一个 SQLite3::execute - $iStmt-execute() - 的结果没有被分配给任何东西。我没有看到获取和解释该结果的任何特殊原因。当我将该行代码更改为 $rslt = $iStmt->execute() 时,我得到了预期的结果 - 正确报告了插入的三行中的 rowid/id。
就好像 PHP SQLite3 扩展在内部缓冲了来自 SQLiteStatement::execute 函数调用的结果。当我跳过作业时,我下一次尝试运行这样的语句时,$sStmt->execute() 实际上是在获取先前的结果。这是我在不了解 PHP SQLite3 扩展的内部工作原理的情况下的解释。也许更了解扩展的人愿意发表评论。
【问题讨论】:
-
“我在这里做错了什么” 目标是什么?什么不能按预期工作?数据按你说的保存,没有错误。你到底有什么问题?
-
@feeela 看起来 DroidOS 不希望选择语句返回 false。我在打电话,但我认为查询没有在 for 循环中重新初始化。
-
我已经编辑了这个问题,以更好地表明我觉得没有按应有的方式工作。基本上,我需要获取新创建的行/更新行的 rowid。正如@Zev 所说,我看不出为什么
select语句返回false而不是返回SQLite3Result以及为什么- 鉴于它返回false- 没有lastErrorMessage。 -
不是我第一次发现自己被感动写下这些内容 - 投票“关闭”我的问题的人是否愿意评论他们选择投票的原因?如果有什么需要澄清的,可能会被要求。如果我以某种方式违反了这个论坛的规则,没有表现出足够的研究……这也可以表明。点击关闭链接太容易了!
-
@DroidOS 我需要重新安装 PHP 才能在本地使用它,但是您是否尝试将这两行移到 for 循环中:
$iStmt = $sqlite->prepare("INSERT OR IGNORE INTO keywords (lang,kwd) VALUES(:lang,:kwd)"); $sStmt = $sqlite->prepare("SELECT rowid FROM keywords WHERE lang = :lang AND kwd = :kwd");
标签: php sqlite prepared-statement