【问题标题】:C++ DB2 Clearing a non Journal table in QTEMPC++ DB2 在 QTEMP 中清除非日志表
【发布时间】: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


【解决方案1】:

好的,我解决了,我只是在调用strcpy(Query2, "DELETE FROM QTEMP/P6SUBFCH"); 查询之前添加了EXEC SQL SET TRANSACTION ISOLATION LEVEL NO COMMIT;

这是我的完整代码:

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)
    {
         EXEC SQL SET TRANSACTION ISOLATION LEVEL NO COMMIT;

         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;
    }
};

【讨论】:

  • 在语句中实际添加WITH NC 可能会更好。否则,您可能会从其他东西中劫持事务级别。在这一点上,您可能也应该删除 COMMIT 语句。
  • @ X-Zero 我不是很了解 AS400,但是从我用谷歌搜索的 QTEMP 库来看,它只对当前用户可用,在当前会话中,其他用户不能干预正在使用的会话。如果我错了,请纠正我。
  • 正确,QTEMP 仅存在于该作业的上下文中。没有其他工作可以访问它。它在作业开始时创建,在作业结束时连同其内容一起消失。为什么要对私人消失的实体发出 COMMIT?
  • 好吧,我看不出有什么理由应该把它拿出来。有了这个WITH NC,它有什么作用?
  • WITH NC 基本上说,“这个声明不关心交易”。这样您就不会从 else 继承事务级别,如果您的方法之外的方法正在事务中运行。我不担心您的 QTEMP 表本身(无论如何它应该是安全的),我担心运行代码的 rest。交易被认为是首要问题,而不是“本地”问题。如果您设置事务级别(和/或发布手册COMMITs),您可能会在其他地方导致意外行为。
猜你喜欢
  • 2011-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-07
  • 2011-07-30
相关资源
最近更新 更多