3

我正在使用 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 * 我需要select count( columns )- 但我在哪里加入以便我可以计算列?我四处寻找,但找不到我需要的加入。

谢谢,布莱斯斯坦伯格

4

3 回答 3

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可以告诉您临时表中的列的信息。这与“没有这样的表”不太一样,但它相当接近。

于 2013-03-19T23:53:56.383 回答
1

我在 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
于 2013-03-22T14:46:01.127 回答
0

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

1) CREATE TABLE yourtemp_chck SELECT * FROM yourtemp where 1=2; 2) 检查 sys 表的列数 3) 删除 yourtemp_chck

虽然我没有尝试从临时表创建一个真实的表,但确实适用于 v12.10 的真实表。

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

于 2013-11-12T11:25:02.120 回答