【发布时间】:2012-08-07 12:09:32
【问题描述】:
我正在开发一个 C++ 程序来获取和过滤数据,并将其存储到 DB2 AS400 上 QTEMP 库中的临时表 (P6SUBFCH) 中。
这样做的原因是,我们使用 PLEX,它有一个定义的方法来一次获取 64 条记录的块中的数据,所以调用 SQLBlockFetch 的函数将所有记录提取到一个临时表中,并且只返回 64 条记录一次从这个临时表中,并按此处理。
我正在开发自己的 SQLBockfetch,其中的 C++ 部分使用嵌入式 SQL 来执行所有 SQL 查询。它正在获取在 QTEMP 库中创建表 (P6SUBFCH) 的所有数据。
QTEMP 库在会话中处于活动状态,一旦会话结束,所有表都将删除到该库中。
另外需要注意的是,QTEMP 中的所有表都没有记录,从我在 google 上的研究来看是不可能的。
问题
我的 C++ 程序第一次在会话中调用时运行良好,但第二次它只是将数据附加到表 QTEMP/P6SUBFCH 中的先前数据。这是一个问题,我尝试先清除数据(SQL DELETE 语句),但我在 AS400 作业日志中收到此 SQL 错误。
Member P6SUBFCH not journaled to journal *N.
P6SUBFCH in QTEMP not valid for operation.
SQL 错误:-7008
我已阅读以下ql7008-error-workaround
禁用事务隔离
不确定这是否是我的问题?我还是嵌入式 SQL 的新手,不知道该怎么做。
这是我的代码:
void LinkRepository::SaveResultsToTable(InputParameters inputParameters)
{
EXEC SQL INCLUDE SQLCA;
EXEC SQL BEGIN DECLARE SECTION;
char Query2[2000] = { "" };
char Query3[2000] = { "" };
EXEC SQL END DECLARE SECTION;
strcpy(Query2, "CREATE TABLE QTEMP/P6SUBFCH");
strcat(Query2, " (PAOPIID CHAR(21) NOT NULL,");
strcat(Query2, " POPITPE CHAR(10),");
strcat(Query2, " POPISTPE CHAR(10),");
strcat(Query2, " POPIKNID CHAR(20),");
strcat(Query2, " PINSTAT CHAR(10),");
strcat(Query2, " PLEAFIND CHAR(1),");
strcat(Query2, " CLOPIID CHAR(21),");
strcat(Query2, " COPITPE CHAR(10),");
strcat(Query2, " COPISTPE CHAR(10),");
strcat(Query2, " COPIKNID CHAR(20),");
strcat(Query2, " CINSTAT CHAR(10),");
strcat(Query2, " CLEAFIND CHAR(1),");
strcat(Query2, " LINKIN CHAR(10))");
EXEC SQL EXECUTE IMMEDIATE :Query2;
// Error handling
if (sqlca.sqlcode == -601)
{
strcpy(Query2, "DELETE FROM QTEMP/P6SUBFCH");
EXEC SQL EXECUTE IMMEDIATE :Query2;
}
EXEC SQL COMMIT;
// Datalinks is a vector that has all the filter data to insert into the QTEMP/P6SUBFCH table
for(vector<Datalink*>::iterator dl = Datalinks.begin(); dl != Datalinks.end(); ++dl)
{
EXEC SQL SET TRANSACTION ISOLATION LEVEL NO COMMIT;
strcpy(Query3, "INSERT INTO QTEMP/P6SUBFCH (PAOPIID,POPITPE,");
strcat(Query3, "POPISTPE,POPIKNID,PINSTAT,PLEAFIND,");
strcat(Query3, "CLOPIID,COPITPE,COPISTPE,COPIKNID,CINSTAT,");
strcat(Query3, "CLEAFIND,LINKIN)");
strcat(Query3, "VALUES('");
strcat(Query3, (*dl)->ParentOperationsItemId);
strcat(Query3, "','");
strcat(Query3, (*dl)->ParentOperationsItemType);
strcat(Query3, "','");
strcat(Query3, (*dl)->ParentOperationsItemSubType);
strcat(Query3, "','");
strcat(Query3, (*dl)->ParentKnownbyId);
strcat(Query3, "','");
strcat(Query3, (*dl)->ParentInternalStatus);
strcat(Query3, "','");
append_char(Query3, (*dl)->ParentLeafIndicator);
strcat(Query3, "','");
strcat(Query3, (*dl)->ChildOperationsItemId);
strcat(Query3, "','");
strcat(Query3, (*dl)->ChildOperationsItemType);
strcat(Query3, "','");
strcat(Query3, (*dl)->ChildOperationsItemSubType);
strcat(Query3, "','");
strcat(Query3, (*dl)->ChildKnownbyId);
strcat(Query3, "','");
strcat(Query3, (*dl)->ChildInternalStatus);
strcat(Query3, "','");
append_char(Query3, (*dl)->ChildLeafIndicator);
strcat(Query3, "','");
strcat(Query3, (*dl)->LinkInternalStatus);
strcat(Query3, "')");
EXEC SQL EXECUTE IMMEDIATE :Query3;
EXEC SQL COMMIT;
}
};
【问题讨论】:
-
可能有更好的解决方案。请首先解释为什么需要临时表。拿到这些记录后,你在做什么?你是如何在你提到的过程中获取记录的?
-
我们调用 Blockfetch 函数,至少 2 次。第一次调用它时,它调用 C++ 函数来填充临时表,并返回该表的前 64 条记录。然后它第二次返回下一个 64,或者第一个 64 块之上的下一个记录,否则它返回一个状态,让我们知道它已经获取了所有记录。我们将这些记录用于我们系统中的验证功能。希望这能更多地解释我们如何从数据库中获取数据。
-
希望这意味着您的函数正在执行单个 SQL
FETCH FROM CURSOR x FOR 64 ROWS,该语句的单次使用会将包含 64 条记录的块带回数组中。假设 SQL 能够直接为您将行插入到临时表中,而无需先获取它们,甚至一次性完成而不是一次 64 行? -
那我们首先看看你对临时表中的记录做了什么。请解释一下。也许您重新排序、汇总、加入另一个或更多表。可能是您的 BlockFetch 中的 SQL 可以更改为您提供您想要的结果,就好像它们来自临时表一样。在许多情况下,可以编写一个 SELECT 来完成在临时工作文件中完成的工作。您也许可以消除构建临时表并从中重新获取数据的中间步骤。如果可能的话,这可以大大简化您的程序。
-
例如,如果您的程序正在读取 X 以放入临时表 Y 以在表 Z 上插入、更新或删除,并且没有副作用(例如其他表已更改),那么您通常可以重写 SQL 以从 X 转到 Z,而无需 Y。临时表通常可以通过在原始 SELECT 语句中添加更多逻辑来消除。这使 SQL 优化器有机会决定产生结果的最佳方式,并且它有时可以在幕后为您进行一些非常复杂的处理。如果存在适当的索引,则尤其如此。
标签: c++ sql db2 ibm-midrange