2012-04-12 56 views
3

我的工作要求我创建一个从原始表影子表的一个巨大的名单审核跟踪模块上创建影子表。我正在考虑编写一个可以从另一个表生成影子表的存储过程。这个表可以是任何表,它可以是由任何数据类型的3个字段组成的table_A,或者由任何数据类型的10个字段组成的table_B,并且可以基于参数传入存储过程。如何在Informix的

我知道我可以检索的syscolumns和SYSTABLES这样提供给特定的表-A字段列表:

select * from syscolumns where tabid = (select tabid from systables where tabname='table_A') 

会有字段列表从这句话返回,让说field_A,然后我将重命名此field_A以创建2个新字段,即pre_field_A和post_field_A,然后使用这两个新字段创建shadow_table_A的影子表。将这个概念应用于其他领域。不用担心字段的数据类型,因为这些信息已经存在于syscolumns中,我可以将其复制到影子表中。

我目前被困在如何存储上述语句返回的值列表,因为通常任何表都将包含多个字段。它可以使用数组完成吗?或者为审计跟踪目的创建影子表的任何备用解决方案?

回答

3

您的查询的工作,但它可能是更地道使用连接:

SELECT * 
    FROM "informix".systables AS t 
    JOIN "informix".syscolumns AS c ON t.tabid = c.tabid 
WHERE t.tabname = 'table_a'; 

而且,要知道,在系统目录仅包含table_A在混合情况下,如果你创建的表,而你有DELIMIDENT在环境中设置,并且您使用双引号括起来的名称创建表。通常,表名将在系统目录中以小写字母表示;类似的列名称。

然而,这一切都相切你的问题。处理用户定义的所有类型都是很痛苦的。但是,如果您正在处理普通数据库,那么当然可以这样工作,但使用DB-Schema(dbschema)可能更容易为表生成模式,然后进行陷阱。你实际上可以通过使用SYSTEM语句的存储过程来做到这一点,但我可能会从存储过程之外做到这一点。这取决于你需要做什么。每个领域的前映像和后映像可能会适度地增加成本。

如果您有IBM Informix Dynamic Server 11.70,则可以动态创建CREATE {audit} TABLE语句,然后执行该语句。因此,您将在存储过程中使用FOREACH循环来构建查询,以依次添加每个列,然后执行该语句以创建审计表。你也必须解码类型。你也可以/应该为此使用一个程序。我假设tabnamec_colname传递到存储过程的变量,并且c_colno,和c_typename是局部变量(如cts,简称“create table语句”,并pad):

LET cts = 'CREATE TABLE ' || tabname || '('; 
LET pad = ''; 
FOREACH SELECT c.colno, c.colname, type_name(c.coltype, c.collength) 
      INTO c_colno, c_colname, c_typename 
      FROM "informix".systables AS t 
      JOIN "informix".syscolumns AS c 
      ON t.tabid = c.tabid 
     WHERE t.tabname = tabname 
     ORDER BY c.colno 
    LET cts = cts || pad || 'pre_' || c_colname || ' ' || c_coltype; 
    LET cts = cts || ',' || 'post_' || c_colname || ' ' || c_coltype; 
    LET pad = ','; 
END FOREACH; 
LET cts = cts || ');'; 

你可能想要处理NOT NULL和主键约束以及其他各种各样的事情,但是这会给你提供一些基础知识。

+0

我可以知道如何在存储过程中执行cts语句吗? – huahsin68 2012-04-12 06:22:41

+1

'EXECUTE IMMEDIATE cts;' – 2012-04-12 06:24:15

+0

如果你用'Informix 11.50'执行这个''cts'变量会重写每一列(在每个'foreach'中),这是正常行为吗? – 2014-08-21 15:33:45

2

除了JonathanLeffleranswer,有type_name程序:

CREATE PROCEDURE type_name(coltype INTEGER, colsize INTEGER) 
      RETURNING VARCHAR(128); 
      DEFINE toRet     VARCHAR(128); 

      DEFINE size_5     VARCHAR(5); 
      DEFINE decimal_p, decimal_s  INTEGER; 
      DEFINE decimal_t    VARCHAR(16); 
      DEFINE varchar_m, varchar_n  INTEGER; 
      DEFINE varchar_t    VARCHAR(16); 

      LET size_5 = '(' || TRIM(CAST(colsize AS CHAR(5))) || ')'; 
      -- Precision 
      LET decimal_p = TRUNC(colsize/256); 
      -- Scale 
      LET decimal_s = colsize - 256 * decimal_p; 
      -- Decimal total 
      LET decimal_t = '(' || TRIM(CAST(decimal_p as VARCHAR(8))) || ',' || TRIM(CAST(decimal_s as VARCHAR(8))) || ')'; 

      -- VARCHAR(M,N) 
      LET varchar_n = decimal_p; 
      LET varchar_m = decimal_s; 
      LET varchar_t = '(' || TRIM(CAST(varchar_m as VARCHAR(8))) || ',' || TRIM(CAST(varchar_n as VARCHAR(8))) || ')'; 

      SELECT 
       CASE coltype 
        WHEN 0 THEN 'char' || size_5 
        WHEN 1 THEN 'smallint' 
        WHEN 2 THEN 'integer' 
        WHEN 3 THEN 'float' 
        WHEN 4 THEN 'smallfloat' 
        WHEN 5 THEN 'decimal' || decimal_t 
        WHEN 6 THEN 'serial' 
        WHEN 7 THEN 'date' 
        WHEN 8 THEN 'money' || decimal_t 
        WHEN 9 THEN 'null' 
        WHEN 10 THEN 'DATETIME YEAR TO FRACTION(3)' 
        WHEN 11 THEN 'byte' 
        WHEN 12 THEN 'TEXT' 
        WHEN 13 THEN 'VARCHAR' || varchar_t 
        WHEN 14 THEN 'INTERVAL' 
        WHEN 15 THEN 'NCHAR' || size_5 
        WHEN 16 THEN 'NVARCHAR' || varchar_t 
        WHEN 17 THEN 'INT8' 
        WHEN 18 THEN 'SERIAL8' 
        WHEN 19 THEN 'SET' 
        WHEN 20 THEN 'MULTISET' 
        WHEN 21 THEN 'LIST' 
        WHEN 22 THEN 'ROW' 
        WHEN 23 THEN 'COLLECTION' 
        WHEN 24 THEN 'ROWDEF' 
        WHEN 40 THEN 'LVARCHAR' || size_5 
        WHEN 256 THEN 'CHAR' || size_5 || ' NOT NULL' 
        WHEN 257 THEN 'SMALLINT NOT NULL' 
        WHEN 258 THEN 'INTEGER NOT NULL' 
        WHEN 259 THEN 'FLOAT NOT NULL' 
        WHEN 260 THEN 'SMALLFLOAT NOT NULL' 
        WHEN 261 THEN 'DECIMAL' || decimal_t || ' NOT NULL' 
        WHEN 262 THEN 'SERIAL NOT NULL' 
        WHEN 263 THEN 'DATE NOT NULL' 
        WHEN 264 THEN 'MONEY' || decimal_t || ' NOT NULL' 
        WHEN 265 THEN 'null NOT NULL' 
        WHEN 266 THEN 'DATETIME YEAR TO FRACTION(3) NOT NULL' 
        WHEN 267 THEN 'BYTE NOT NULL' 
        WHEN 268 THEN 'TEXT NOT NULL' 
        WHEN 269 THEN 'VARCHAR' || varchar_t || ' NOT NULL' 
        WHEN 270 THEN 'INTERVAL NOT NULL' 
        WHEN 271 THEN 'nchar(' || size_5 || ') NOT NULL' 
        WHEN 272 THEN 'nvarchar' || varchar_t || ' NOT NULL' 
        WHEN 273 THEN 'int8 NOT NULL' 
        WHEN 274 THEN 'serial8 NOT NULL' 
        WHEN 275 THEN 'set NOT NULL' 
        WHEN 276 THEN 'multiset NOT NULL' 
        WHEN 277 THEN 'list NOT NULL' 
        WHEN 278 THEN 'row NOT NULL' 
        WHEN 279 THEN 'collection NOT NULL' 
        WHEN 280 THEN 'rowdef NOT NULL' 
        WHEN 296 THEN 'LVARCHAR' || varchar_t || ' NOT NULL' 
        ELSE 'ERROR' 
       END datatype 
      INTO toRet 
      FROM systables 
      WHERE tabid = 1; 
      IF toRet = 'ERROR' THEN 
       RAISE EXCEPTION -746, 0, 'Unknow datatype ' || coltype; 
      END IF 

      RETURN toRet; 
    END PROCEDURE; 

感谢this

+0

谢谢。 “CASE 2”是否正确?它不总是返回'整数'?我认为它应该是'CASE coltype'。类似地,在末尾的'ELSE'子句中的CAST(2 ...)中,代码不解码DATETIME或INTERVAL;它也不识别[N] VARCHAR(255,3)符号我认为这是1023的大小) – 2014-08-21 19:01:47

+0

修正了'CASE 2'(它用于调试目的),在'VARCHAR(M,N)'的情况下,长度是'1023',是正确的:'M = colsize-256 * N'和'N = TRUNC(colsize/256)'?,感谢您的帮助,我是informix的新手。 – 2014-08-22 14:39:35

+0

是的;低位8位编码的总长度[N] VARCHAR列,并且高阶8位(通常为零)编码最小长度。 – 2014-08-22 16:29:37