2012-04-12 57 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