【问题标题】:Informix: count number of columns in a temp table?Informix:计算临时表中的列数?
【发布时间】:2013-03-19 23:34:00
【问题描述】:

我使用的是 IDS 11.70。

我希望能够获取临时表中列数的计数,因此在 4gl/genero 代码中,我可以使用一个函数将正确数量的问号放入“放置游标”语句中。

例如,想替换这种代码:

    declare put_curs1 cursor for
    insert into my_temp_table values(?,?,?,?,?,?)

这样的:

let str = "insert into my_temp_table values (
    format_place_holder_string_for_insert( "my_temp_table" ) CLIPPED, ")"
prepare put_stment1 from str
declare put_curs1 cursor for put_stment1

我们已经为我们的常规表执行了此操作,因此如果应该将表架构更改为包含更多或更少的列,那么代码不会因使用 put 游标插入错误的列数而中断。 在常规表的此函数中,要获取我们使用的列数:

   select count(*)
    from systables, syscolumns
    where systables.tabname = table_name
    and systables.tabid = syscolumns.tabid

但在尝试对临时表执行此操作时,我看不到我加入的内容或指示临时表中有多少列的列。这是我目前所拥有的:

select *
FROM sysmaster:systabnames n, sysmaster:systabinfo i, sysmaster:syssessions s 
WHERE sysmaster:bitval(i.ti_flags, "0x0020") = 1 
AND n.dbsname = database_name
AND i.ti_partnum = n.partnum 
AND s.sid = dbinfo("sessionid")
AND n.tabname = table_name;

所以我需要select count( columns ) 而不是select * - 但是我应该加入哪里才能计算列数?我四处寻找,但找不到我需要的加入。

谢谢, 布莱斯·斯坦伯格

【问题讨论】:

    标签: informix


    【解决方案1】:

    经典的方法是准备'SELECT * FROM temptable',描述语句,并从描述中获取列数,然后释放准备好的语句。这涉及到下降到 ESQL/C,虽然......或者很可能这样做。

    未经测试的代码——带有松散到不存在的错误检查:

    int cols_in_temp_table(int nargs)
    {
        $ char buffer[300];
        struct sqlda *u;
        char tabname[129];
        if (nargs != 1)
            ibm_lib4gl_fatalError(...);
        popstring(tabname, sizeof(tabname));
        sprintf(buffer, "SELECT * FROM %s", tabname);
        $ PREPARE p FROM :buffer;
        $ DESCRIBE p INTO u;
        retint(u.sqld);
        $ FREE p;
        free(u);
        return(1);
    }
    

    在 I4GL 中调用:

    DEFINE n INTEGER
    
    LET n = cols_in_temp_table("the_temp_table")
    

    代码实际上适用于任何表,无论是否为临时表,因此函数名称有点用词不当。

    我在sysmaster 数据库中找不到任何可以告诉您临时表中的列的信息。这与“没有这样的表”不太一样,但它相当接近。

    【讨论】:

    • 您好 Jonathan,在我们的环境中,我们不使用任何 ESQL/C,因此我无法实施您的解决方案。我们只使用 Genero 进行编码。数据库必须知道某个地方的临时表中有哪些列,也许有人知道在哪里可以找到它...谢谢您的回复。问候,布莱斯斯坦伯格。
    【解决方案2】:

    我在 ifx 11.50 FC9 上成功测试了下面的代码。

    WARNING: 我使用了一个未记录的函数。我不知道在生产中使用它是否安全......

    工作原理:我将行“转换”为 ROW 数据类型;使用名为 collectionoutput 的内部函数将此 ROW 转换为 lvarchar,然后计算逗号有多少(列分隔符)。

    Pre-req : 创建/运行函数的权限;临时表必须至少有 1 行。

    --drop function count_cols;
    create function count_cols ( cols lvarchar(4000) ) returning int ;
      define i int;
      define ncols int;
      define isstring int;
      let ncols = 1;
      let isstring = 0;
    
      for i = 1 to length(cols)
        if substr(cols,i,1) = "'"  and isstring = 1 then
          let isstring = 0 ;
          continue for;
        end if ;
        if substr(cols,i,1) = "'"  and isstring = 0 then
          let isstring = 1 ;
          continue for;
        end if ;
        if isstring = 0 and substr(cols,i,1) = ',' then
           let ncols = ncols+1 ;
        end if ;
      end for ;
      return ncols;
    end function
    ;
    
    
    --drop table t2;
    create temp table t2 ( cod int, desc char(100) default 'test', data datetime year to second default current year to second , number int);
    insert into t2 (cod)values (0);
    insert into t2 (cod)values (0);
    insert into t2 values (1,'teste,teste,teste,teste',current, 0);
    
    select * from t2;
    select collectionoutput(multiset(select first 1 * from t2 where cod = 1)) from sysmaster:sysdual ;
    select count_cols(collectionoutput(multiset(select first 1 * from t2 where cod = 1))) from sysmaster:sysdual;
    

    我的输出 (dbaccess)

    cod     0
    desc    test
    data    2013-03-22 11:36:37
    number
    
    cod     0
    desc    test
    data    2013-03-22 11:36:37
    number
    
    cod     1
    desc    teste,teste,teste,teste
    data    2013-03-22 11:36:37
    number  0
    
    (expression)  MULTISET{ROW(1          ,'teste,teste,teste,teste
                                                                               ','2
                  013-03-22 11:36:37',0          )}
    
    (expression)
    
               4
    

    【讨论】:

    • 您好,很抱歉这么久才回复。
    • 您好,很抱歉这么久才回复。我在上面尝试了您的代码,它可以工作。但是,当我尝试将它与使用select * from myTable into temp TmpMyTable with no log 创建的真实临时表之一一起使用时,我收到Error Code: -9930, Byte, Text, Serial, Serial8 or Bigserial datatypes in collection types not allowed. 的错误我们在很多表中使用串行,所以它看起来很有希望,但不适合我的情况。我认为未记录的功能是'collectionoutput'?我可能会将这个问题带到 IIUG 列表以获得更多想法。谢谢,布莱斯。
    【解决方案3】:

    仅供参考 - 如果使用 12.10 - 可以创建临时表的真实实例并从系统表中获取列数。

    1) 创建表 yourtemp_chck SELECT * FROM yourtemp where 1=2; 2) 检查 sys 表的列数 3) 删除你的temp_chck

    虽然我没有尝试从临时表创建一个真实的表,但确实可以在 v12.10 中使用 real from real。

    在任何版本中也可以只创建真正的表,以便可以从系统表中获取列数并在之后删除。我已经在非常古老的 4GL 中看到了这一点。除非没有其他选择,否则我不会做任何事情。

    【讨论】:

    • 感谢您的想法 - 我会在有时间的时候尝试一下,尽管目前仅运行 11.70。一旦我尝试过,我会在这里再次发表评论。干杯,布莱斯。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2013-12-02
    • 2017-09-23
    • 1970-01-01
    • 2015-01-08
    • 1970-01-01
    相关资源
    最近更新 更多