存储过程与系统表

时间:2016-02-08 12:35:16

标签: sql sql-server stored-procedures informix

我的数据库中有两个不同的系统表:Systables(存储数据库的所有表)和Syscolumns(存储数据库表的所有列)。

  • Systables包含:tabname和tabid;
  • Syscolumns包含:colname,tabid,colno。

我必须编写以下程序:

  • 我有2个新表 - Tabela_sys(包含ns_tabela和nome)和Campo_sys(ns_campo,ns_tabela,nome)。
  • 我想存储tabela_sys中不存在的systables数据,我想存储Campo_Sys中不存在的syscolumns数据。
  • 为此,我做了以下过程,并测试了一个案例,其中我在现有表中创建了一个新列。
  • 预计执行我的程序后,Tabela_sys将保持行数相等,Campo_sys将识别1个新行。

在执行此过程后,它没有发生,Campo_sys还有更多行。

有谁知道可能出现什么问题?

CREATE PROCEDURE test ()

DEFINE cont       INTEGER;
DEFINE cont2       INTEGER;
DEFINE TabIdNum       INTEGER;
DEFINE varTabName,aa       VARCHAR (50,0);
DEFINE Nstabela       INTEGER;
DEFINE StrColName       VARCHAR (50,0);
DEFINE ColIdNum       INTEGER;

    FOREACH cur1 WITH HOLD FOR

        SELECT  tabid, tabname
        INTO    TabIdNum,varTabName
        from    systables
        WHERE   tabname not matches "sys*"

        --let aa=varTabName;

        SELECT  count(*), ns_tabela
        INTO cont, Nstabela
        FROM tabela_sys
        WHERE nome = varTabName
        GROUP BY 2;

        --let Nstabela=0;

        IF cont = 0 or cont is null THEN    
            INSERT INTO tabela_sys (ns_tabela, nome) 
            VALUES (0, varTabName);

            SELECT dbinfo('sqlca.sqlerrd1')
            INTO   Nstabela
            FROM   systables
            WHERE  tabname='systables';
        END IF;

    FOREACH cur2 WITH HOLD FOR

        SELECT  tabid, colname 
        INTO    ColIdNum, StrColName
        FROM    syscolumns 
        WHERE   tabid = TabIdNum        
        --AND   colname NOT IN (SELECT nome FROM campo_sys WHERE ns_tabela = Nstabela)  

        SELECT  count(*)
        INTO cont2
        FROM campo_sys
        WHERE nome = StrColName
        and   ns_tabela = Nstabela;

        --let Nscampo=0;

        IF cont2 = 0 or cont2 is null  THEN 
            INSERT INTO campo_sys (ns_tabela, nome) --(ns_campo, ns_tabela, nome) 
            VALUES (ColIdNum, StrColName); --(0, ColIdNum, StrColName);

        END IF;

    END FOREACH

    END FOREACH

END PROCEDURE;

2 个答案:

答案 0 :(得分:0)

当然,tabela_syscampo_sys的行数会有所不同,因为foreach中的每个列都会运行第二个syscolumns,并且每当找到新列时对于表格,插入了campo_sys

在使用现有程序时,除非表的syscolumns为1(表示我认为不理想的情况下表中的一列),否则您的要求永远不会给出相同数量的记录。

PS:我没有足够的声誉发表评论,因此在此处添加了答案。如果它回答了你的问题,你可以接受答案;)

答案 1 :(得分:0)

对手术有很多误解。

首先,不要使用:

WHERE   tabname not matches "sys*"

如果有人创建了一张桌子,让我们说system_dest,你就不会抓住它。

排除系统表的最安全方法是:

WHERE   tabid > 99;

数据库中第一个用户定义的表对象的 tabid 始终为 100 。并且目录表不以 sys 开头,例如: GL_COLLATEGL_CTYPEVERSION

您正在创建新的序列而不是使用系统序列;你打算保留历史吗?如果有人丢弃一个表并使用相同的名称重新创建一个新表,这可能是错误的。

如果没有找到记录,您只会更新,这意味着如果上述情况发生,您将无法更新。如果有人丢弃或添加新列,它将不会反映在您的表格上。

您的第二个 foreach 有一个逻辑问题:

    SELECT  tabid, colname 
    INTO    ColIdNum, StrColName
    FROM    syscolumns 
    WHERE   tabid = TabIdNum        

在此snipet中,您将存储 tabid colname

然后,您可以使用名称和您指定的 ID 而不是系统的 tabid 来计算campo_sys上的匹配项。因此它总是 0

    SELECT  count(*)
    INTO cont2
    FROM campo_sys
    WHERE nome = StrColName
    and   ns_tabela = Nstabela;

最后,您插入campo_sys存储系统的 tabid colname

INSERT INTO campo_sys (ns_tabela, nome) --(ns_campo, ns_tabela, nome) 
VALUES (ColIdNum, StrColName); --(0, ColIdNum, StrColName);

这就是为什么每次运行该过程时都会再次插入所有列。

您是否考虑对目录表使用视图

CREATE VIEW tabela_sys (ns_tabela, nome) AS
    SELECT  tabid, tabname
    FROM    systables
    WHERE   tabid > 99;

CREATE VIEW campo_sys (ns_campo, ns_tabela, nome) AS
        SELECT  colno, tabid, colname
        FROM    syscolumns
        WHERE   tabid > 99;

如果需要物理表,最佳选择是使用Merge Statement