楼主: yulihua49

[PRO*C] 看我做的数据库包装器

[复制链接]
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
471#
发表于 2010-2-24 01:37 | 只看该作者
测试结果:

全自动软软解析:
BEGIN
   FOR I IN 1..100000 LOOP
       INSERT INTO T VALUES (I,I,I,I);
   END LOOP;
END;
/

PL/SQL procedure successfully completed.

Elapsed: 00:00:04.03


手动打开并保持游标:
declare
   v_sql varchar2(200);
   l_theCursor   integer;
   l_status      integer;
begin

  v_sql:='INSERT INTO T VALUES (:c1,:c2,:c3,:amount)';  
   
  l_theCursor := dbms_sql.open_cursor;
  
  dbms_sql.parse( c => l_theCursor,
                  statement => v_sql,
                  language_flag => dbms_sql.native
                 );

   FOR I IN 1..100000 LOOP
        dbms_sql.bind_variable( c => l_theCursor,
                                name => ':c1',
                               value => i
                              );   
        dbms_sql.bind_variable( c => l_theCursor,
                                name => ':c2',
                               value => i
                              );   
        dbms_sql.bind_variable( c => l_theCursor,
                                name => ':c3',
                               value => i
                              );   
        dbms_sql.bind_variable( c => l_theCursor,
                                name => ':amount',
                               value => i
                              );   
        l_status := dbms_sql.execute(l_theCursor);
  end loop;

  dbms_sql.close_cursor( c => l_theCursor );

end;
/


PL/SQL procedure successfully completed.
Elapsed: 00:00:07.89

结论:DIY方法总是要差一点。

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
472#
 楼主| 发表于 2010-2-24 10:17 | 只看该作者
原帖由 newkid 于 2010-2-23 23:47 发表
如果仅仅是数据加载,不涉及任何事务处理逻辑,映射到结构就没什么意义,一个二维数组就够了。你需要的只是一个缓存,从文件读入,再送给目标数据库。
通用的数据抽取转换工具已经很多了,我只要使用就行。

你的意思是手工处理游标更快?等我有空比较一下。

hibernate我们是不用的,看不到任何好处。我们大量使用存储过程。

看模板时,知道此表如此。----- 如果有聚合,或者多表连接,你就不能用表模板了,你看到的已经不是表结构了
看程序时,如此访问此表。逻辑很清晰。------- 同上,如果是复杂SQL,你还得回头再去看模板才有意义。

可见用了你的DAU,你就会培养出一堆只知道单表操作的程序员。

那个席位发布程序报什么错?让它出错的运行步骤是什么?我自己的测试结果(连续运行两次程序),第二次什么数据也不产生而且不报错。


绑定变量需要空间,DAU_init分析了表结构后形成模板,然后按模板形成buffer,这个buffer就是一个结构布局。
然后,DAU_dispack就把字符串数据拆包到这个buffer,DAU_insert就把这个buffer绑定。这处处都要用模板,否则你怎么知道都有多少列,各是什么类型,多长,什么格式?你自己分析,然后分配空间,然后绑定变量?这不正是DAU帮你做的吗?

make_seats(null,0,0,1);
ERROR at line 1:
ORA-00001: unique constraint (TICKET.SYS_C0017007) violated
ORA-06512: at "TICKET.MAKE_SEATS", line 23
ORA-06512: at line 11


看模板时,知道此表如此。----- 如果有聚合,或者多表连接,你就不能用表模板了,你看到的已经不是表结构了
看程序时,如此访问此表。逻辑很清晰。------- 同上,如果是复杂SQL,你还得回头再去看模板才有意义。

可见用了你的DAU,你就会培养出一堆只知道单表操作的程序员。”
我就知道你会这么说,我一再一再说,DAU支持多表集合操作,一个结构对应的“表”是广义的,前边说了,有“表 表达式”你理解是什么含义吗?

看一下DAU内部分析表结构的模板:
static T_PkgType PATTERN_type[]={
        {CH_CHAR,49,"c.table_name table_name",0,-1},
        {CH_CHAR,83,"c.column_name column_name"},
        {CH_SHORT,sizeof(short),
                "decode(data_type, 'CHAR',1, 'VARCHAR',1, 'VARCHAR2',1, 'DATE',129,'TIMESTAMP(6)',129,"
                "'FLOAT',8,'LONG',126, 'RAW',0, 'BINARY_DOUBLE',8,'BINARY_FLOAT',7,"
                                " 'NUMBER',decode(nvl(DATA_SCALE,0),0, "
                "decode(nvl(data_precision,0), 0,257, 1,2, 2,2, 3,3, 4,3, 5,4, 6,4, 7,4, 8,4,"
                "9,4, 10,6, 11,6, 12,6, 13,6, 14,6, 15,6, 16,6, 17,6, 18,6, 257),8),257) "
                "Fld_Column_Type"},
        {CH_SHORT,sizeof(short),"decode(data_type, 'CHAR',data_length+1, 'VARCHAR',data_length+1,"
                "'VARCHAR2',data_length+1, 'DATE',20,'TIMESTAMP(6)',27,'FLOAT',8,'BINARY_DOUBLE',8,'BINARY_FLOAT',4, "
                                "'LONG',-1, 'NUMBER', "
                "decode(nvl(DATA_SCALE,0),0,decode(nvl(data_precision,0), 0,35, 1,1, 2,1, 3,2, "
                "4,2, 5,4, 6,4, 7,4, 8,4, 9,4, 10,8, 11,8, 12,8, 13,8, 14,8, 15,8, 16,8, 17,8, "
                "18,8, data_precision+2),8),data_length) "
                                "Fld_Column_Len"},
        {CH_CHAR,30,"decode(data_type, 'CHAR',null, 'VARCHAR',null, 'VARCHAR2',null, "
                "'DATE','YYYY-MM-DD HH24:MI:SS','TIMESTAMP(6)','YYYY-MM-DD HH24:MI:SS.FF6','FLOAT','%lg','LONG',null, "
                "'BINARY_DOUBLE','%lg', 'BINARY_FLOAT','%g', 'NUMBER',decode(nvl(DATA_SCALE,0),0,null,"
                "'%'||TO_CHAR(data_precision+2)||'.'||TO_CHAR(DATA_SCALE)||'lf'),null) "
                "Fld_Format"},
        {CH_SHORT,sizeof(short),"k.position"},
        {-1,0,0,0}
};
就是一个多表的列表达式。

  1. //PATTERN_s *pp是与上述模板对应的数据结构。
  2. typedef struct  {
  3.         char Fld_Tlb_Name[49];
  4.         char Fld_Column_Name[83];
  5.         short Fld_Column_Type;
  6.         short Fld_Column_Len;
  7.         char Fld_Format[30];
  8.         short Fld_PK;
  9. } PATTERN_s;

  10. static int descDAO(DAU *DP,T_SQL_Connect *SQL_Connect,PATTERN_s *pp,char *stmt)
  11. {
  12. int ret;
  13. char pattTable[256];

  14. // 如果是其它数据库,要改。
  15. //生成表名表达式。
  16.         strcpy(pattTable, "all_tab_columns c, "
  17.                 "(select table_name,column_name,position "
  18.                  "from all_cons_columns "
  19.                  "where owner= :column_name and table_name=:table_name and position is not null) k ");

  20.         DAU_init(DP,SQL_Connect,pattTable, pp,PATTERN_type);
  21. //条件表达式
  22.         strcpy(stmt,"where c.table_name = k.table_name(+) "
  23.                  "and c.column_name = k.column_name(+) "
  24.                  "and c.owner = :column_name and c.table_name=:table_name "
  25.                  "order by c.table_name, c.column_id ");
  26.         ret=DAU_select(DP,stmt,0);
  27. if(ret<=0) ShowLog(1,"descDAO:DAU_select stmt=%s",stmt);
  28.         return ret;
  29. }

复制代码

生成的语句和分析的结果:
5 loadsth:28746 02/23 09:38'00 ,bind_select:cursor=0,sqlo_prepare=SELECT c.table_name table_name,c.column_name column_name,decode(data_type, 'CHAR',1, 'VARCHAR',1, 'VARCHAR2',1, 'DATE',129,'TIMESTAMP(6)',129,'FLOAT',8,'LONG',126, 'RAW',0, 'BINARY_DOUBLE',8,'BINARY_FLOAT',7, 'NUMBER',decode(nvl(DATA_SCALE,0),0, decode(nvl(data_precision,0), 0,257, 1,2, 2,2, 3,3, 4,3, 5,4, 6,4, 7,4, 8,4,9,4, 10,6, 11,6, 12,6, 13,6, 14,6, 15,6, 16,6, 17,6, 18,6, 257),8),257) Fld_Column_Type,decode(data_type, 'CHAR',data_length+1, 'VARCHAR',data_length+1,'VARCHAR2',data_length+1, 'DATE',20,'TIMESTAMP(6)',27,'FLOAT',8,'BINARY_DOUBLE',8,'BINARY_FLOAT',4, 'LONG',-1, 'NUMBER', decode(nvl(DATA_SCALE,0),0,decode(nvl(data_precision,0), 0,35, 1,1, 2,1, 3,2, 4,2, 5,4, 6,4, 7,4, 8,4, 9,4, 10,8, 11,8, 12,8, 13,8, 14,8, 15,8, 16,8, 17,8, 18,8, data_precision+2),8),data_length) Fld_Column_Len,decode(data_type, 'CHAR',null, 'VARCHAR',null, 'VARCHAR2',null, 'DATE','YYYY-MM-DD HH24:MI:SS','TIMESTAMP(6)','YYYY-MM-DD HH24:MI:SS.FF6','FLOAT','%lg','LONG',null, 'BINARY_DOUBLE','%lg', 'BINARY_FLOAT','%g', 'NUMBER',decode(nvl(DATA_SCALE,0),0,null,'%'||TO_CHAR(data_precision+2)||'.'||TO_CHAR(DATA_SCALE)||'lf'),null) Fld_Format,k.position FROM all_tab_columns c, (select table_name,column_name,position from all_cons_columns where owner= :1 and table_name=:2 and position is not null) k  where c.table_name = k.table_name(+) and c.column_name = k.column_name(+) and c.owner = :3 and c.table_name=:4 order by c.table_name, c.column_id

5 loadsth:28746 02/23 09:38'00 mkpk:tjdate|unit|tabname|flg|
耐心仔细看,不是DAU难懂,真正是SQL难懂。
这就是我们先前pk的tjrb表。
我给你导读一下:
分析表结构需要6个值,在模板中6个大括号,前两个比较简单(表名,列名),第3,4,5是复杂表达式,它们分别是类型、长度、格式,将ORACLE的表示法转换为SDBC的表示法。最后一个是主键,另一个表读出来的。
表表达式就是FROM后边的一堆东西。
如此复杂的语句都可以处理,那些count、sum、total,avg...更不在话下。

大家看看,一个支离破碎的SQL好懂呢还是完整语句好懂,看看日志里的那个东西吧(你如果喜欢自己写语句,就是这个东西)。简直是个怪物,不把它五脏六腑掏出来是研究不透的。语句是别人写的,我学习分析,消化了,变成模板,后来在模板的基础上又进行了修改,有了模板修改很方便。比如增加了TIMESTAMP、RAW类型,在原语句上改实在是困难,太容易错了。在改的时候,思路很简单,新类型的类型码,长度,格式。逻辑是非常清晰的。语句分解后带来的好处太大了。
借一句广告语:用了才知道,这正是你需要的。

我可以告诉你SDBC不能做什么:
不能处理BLOB,前导with.....as...的语句,带returnning的语句。
如果需要,在DAU环境下可以调sqlora来处理,也可以调存储过程来处理。SDBC支持你使用存储过程,见我blog里SDBC说明书。
但有些事还要前端做,比如大系统后端是RAC,前端是与数据库分离的应用服务器,涉及局部资源,就无法用存储过程。
SDBC是3层C/S/S模型,所有数据必须序列化,因此有了SRM,有了在SRM基础上的DAU。你不能说什么有用武之地什么没有,它是一个完整系统不可割裂,它需要一个全新的视角(也是最古老的)去看待程序和数据。

[ 本帖最后由 yulihua49 于 2010-2-24 11:44 编辑 ]

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
473#
 楼主| 发表于 2010-2-24 17:36 | 只看该作者

回复 #480 newkid 的帖子

绑定变量可以在循环之外,一次绑定多次使用。
我每次检查一下null 状态,变化了才重新绑定该列。
另外 ,没看见commit。

[ 本帖最后由 yulihua49 于 2010-2-24 17:40 编辑 ]

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
474#
发表于 2010-2-24 23:34 | 只看该作者
我前面不是也写了一个PLSQL加载数据的例子?哪里要用到什么结构?你的DAU做的解析的工作,当然不用DAU也一样完成,我也没有说不用DAU工作量就更小,只是说结构在这个应用中没有什么意义,不是像你说的“自SQL问世,能够把结果集与C结构对应起来,能够把结构与SQL语句结合起来,是无数C程序员的梦寐以求”。

你列出来的那个复杂SQL不过是个纸老虎,在我眼里根本不算什么。用不着你的“导读”我也知道它要干什么。你没有格式化所以看起来很乱。只要你书写规范一点,比如分行、对齐,其实是很好读的。

你这个“内部分析表结构的模板”才难读呢,更不要想是怎么写出来的。

static T_PkgType PATTERN_type[]={
        {CH_CHAR,49,"c.table_name table_name",0,-1},
        {CH_CHAR,83,"c.column_name column_name"},
        ..........
这也只有你和你一帮徒弟会觉得好读。
比如我在你的模板中看到c.table_name, k.position 但是这个模板中并没有告诉你c,k是什么。隔了几条街远的地方才看到:
strcpy(pattTable, "all_tab_columns c, "
                "(select table_name,column_name,position "
                 "from all_cons_columns "
                 "where owner= :column_name and table_name=:table_name and position is not null) k ");
                 
c,k之间的连接关系又看不到了,又得往下找,累不累啊?

另外,我不觉得绑定变量需要判断是否修改过,因为实际应用中变量值往往是变化的,而且主要开销是解析和执行。
我那个插入10万行数据的例子,把绑定移到循环外(也就是说插入10万行一模一样的数据,这在实际中是很少见的),也只节省了半秒钟。


你的seat表上有什么唯一索引?错误是插入了重复数据。我按照这个主键来插入:

start_date
beg_station
Train_no   
Carno      
seat_no   
seat_type

我在一个全新环境中按照你29页的建表语句重新建表、加载数据,再多次运行 make_seats(null,0,0,1); 一点问题也没有。

[ 本帖最后由 newkid 于 2010-2-25 01:05 编辑 ]

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
475#
 楼主| 发表于 2010-2-25 09:33 | 只看该作者
原帖由 newkid 于 2010-2-24 23:34 发表
我前面不是也写了一个PLSQL加载数据的例子?哪里要用到什么结构?你的DAU做的解析的工作,当然不用DAU也一样完成,我也没有说不用DAU工作量就更小,只是说结构在这个应用中没有什么意义,不是像你说的“自SQL问世,能够把结果集与C结构对应起来,能够把结构与SQL语句结合起来,是无数C程序员的梦寐以求”。

你列出来的那个复杂SQL不过是个纸老虎,在我眼里根本不算什么。用不着你的“导读”我也知道它要干什么。你没有格式化所以看起来很乱。只要你书写规范一点,比如分行、对齐,其实是很好读的。

你这个“内部分析表结构的模板”才难读呢,更不要想是怎么写出来的。

static T_PkgType PATTERN_type[]={
        {CH_CHAR,49,"c.table_name table_name",0,-1},
        {CH_CHAR,83,"c.column_name column_name"},
        ..........
这也只有你和你一帮徒弟会觉得好读。
比如我在你的模板中看到c.table_name, k.position 但是这个模板中并没有告诉你c,k是什么。隔了几条街远的地方才看到:
strcpy(pattTable, "all_tab_columns c, "
                "(select table_name,column_name,position "
                 "from all_cons_columns "
                 "where owner= :column_name and table_name=:table_name and position is not null) k ";
                 
c,k之间的连接关系又看不到了,又得往下找,累不累啊?

另外,我不觉得绑定变量需要判断是否修改过,因为实际应用中变量值往往是变化的,而且主要开销是解析和执行。
我那个插入10万行数据的例子,把绑定移到循环外(也就是说插入10万行一模一样的数据,这在实际中是很少见的),也只节省了半秒钟。


你的seat表上有什么唯一索引?错误是插入了重复数据。我按照这个主键来插入:

start_date
beg_station
Train_no   
Carno      
seat_no   
seat_type

我在一个全新环境中按照你29页的建表语句重新建表、加载数据,再多次运行 make_seats(null,0,0,1); 一点问题也没有。


绑定与值无关,绑定在外边值仍然随循环变化。
null状态的判断是必须的。不知存储过程里bind是怎么规定的,在OCI里遇到null必须在表示器指明绑定null,正常值时指明绑定值。
因此如果某列前一条记录是正常,第二个是null,就必须重新声明绑定null,反之亦然。

关于程序风格的争论,永远没结果,各走各路吧。
语句分段以后,把相应段落填写到模板,本来就是这么干的。

根据你的意见,改了一下:历史原因,列名是模板的第三个成员。如果是第一个,就好理解多了。

  1. static T_PkgType PATTERN_tpl[]={
  2.         {CH_CHAR,49,"c.table_name Fld_Tlb_Name",0,-1},
  3.         {CH_CHAR,83,"c.column_name  Fld_Column_Name"},
  4.         {CH_SHORT,sizeof(short),
  5.                 "decode(data_type, 'CHAR',1, 'VARCHAR',1, 'VARCHAR2',1, 'DATE',129,'TIMESTAMP(6)',129,"
  6.                 "'FLOAT',8,'LONG',126, 'RAW',0, 'BINARY_DOUBLE',8,'BINARY_FLOAT',7,"
  7.                 " 'NUMBER',decode(nvl(DATA_SCALE,0),0, "
  8.                 "decode(nvl(data_precision,0), 0,257, 1,2, 2,2, 3,3, 4,3, 5,4, 6,4, 7,4, 8,4,"
  9.                 "9,4, 10,6, 11,6, 12,6, 13,6, 14,6, 15,6, 16,6, 17,6, 18,6, 257),8),257) "
  10.                 "Fld_Column_Type"},
  11.         {CH_SHORT,sizeof(short),"decode(data_type, 'CHAR',data_length+1, 'VARCHAR',data_length+1,"
  12.                 "'VARCHAR2',data_length+1, 'DATE',20,'TIMESTAMP(6)',27,'FLOAT',8,'BINARY_DOUBLE',8,"
  13.                 "'BINARY_FLOAT',4,'LONG',-1, 'NUMBER', "
  14.                 "decode(nvl(DATA_SCALE,0),0,decode(nvl(data_precision,0), 0,35, 1,1, 2,1, 3,2, "
  15.                 "4,2, 5,4, 6,4, 7,4, 8,4, 9,4, 10,8, 11,8, 12,8, 13,8, 14,8, 15,8, 16,8, 17,8, "
  16.                 "18,8, data_precision+2),8),data_length) "
  17.                 "Fld_Column_Len"},
  18.         {CH_CHAR,30,"decode(data_type, 'CHAR',null, 'VARCHAR',null, 'VARCHAR2',null, "
  19.                 "'DATE','YYYY-MM-DD HH24:MI:SS','TIMESTAMP(6)','YYYY-MM-DD HH24:MI:SS.FF6','FLOAT','%lg','LONG',null, "
  20.                 "'BINARY_DOUBLE','%lg', 'BINARY_FLOAT','%g', 'NUMBER',decode(nvl(DATA_SCALE,0),0,null,"
  21.                 "'%'||TO_CHAR(data_precision+2)||'.'||TO_CHAR(DATA_SCALE)||'lf'),null) "
  22.                 "Fld_Format"},
  23.         {CH_SHORT,sizeof(short),"k.position Fld_PK"},
  24.         {-1,0,"all_tab_columns c, "                             //表名表达式
  25.               "(select table_name,column_name,position "
  26.               "from all_cons_columns "
  27.               "where owner= :Fld_Column_Name and "
  28.               "table_name=:Fld_Tlb_Name and position is not null) k ",0}
  29. };

  30. /* auto make pattern */

  31. static int descDAO(DAU *DP,char *stmt)
  32. {
  33. int ret;

  34. // 如果是其它数据库,要改。
  35.         strcpy(stmt,"where c.table_name = k.table_name(+) "
  36.                  "and c.column_name = k.column_name(+) "
  37.                  "and c.owner = :Fld_Column_Name and c.table_name=:Fld_Tlb_Name "
  38.                  "order by c.table_name, c.column_id ");
  39.         ret=DAU_select(DP,stmt,0);
  40.         if(ret<=0) ShowLog(1,"descDAO:DAU_select stmt=%s,err=%d,%s",stmt,
  41.                 DP->SQL_Connect->Errno,DP->SQL_Connect->ErrMsg);
  42.         return ret;
  43. }

复制代码


需要了解SDBC关于模板的规定就容易理解了。你超强的理解力,肯定不要说也看明白了,只是不喜欢此方式而已。
其实模板跟sql语句也差不多,但你写了一个语句,仅仅就是个语句。而模板在程序的许多环节都要用的,是高度可重用代码。
也可以想见,DAU拼装语句的效率是非常高的。

准备给DAU加一个语句前缀,就解决 with...as...select...的问题。

[ 本帖最后由 yulihua49 于 2010-2-25 10:04 编辑 ]

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
476#
发表于 2010-2-25 23:26 | 只看该作者

"绑定与值无关,绑定在外边值仍然随循环变化。"
这可是前所未闻,难道OCI有这功能?典型的过程是解析、绑定、执行。你举出一个最简化的例子,表明一次绑定,修改变量值(但不再次绑定),然后多次执行,数据库会得到不同的数据。

“关于程序风格的争论,永远没结果,各走各路吧。”
这个我是同意的;但具体到你这个例子,你是没什么好争辩的。你列举了一个模板和它生成的SQL, 然后说SQL是多么的不可读。你的SQL生成的时候没有格式化;你的模板包含了整个SQL, 并且还分成了几截,并且又塞进去许多东西,也就是说模板>SQL。为了读懂你的模板我不但要读懂里面的SQL,还必须前后找连贯,还包括其他的如CH_SHORT,sizeof(short),这样的东西,有什么道理说你的模板更好读?

把这个由机器产生的SQL放到TOAD里面格式化一下:
/* Formatted on 2010/02/25 10:18 (Formatter Plus v4.8.8) */
SELECT   c.table_name table_name, c.column_name column_name,
         DECODE (data_type,
                 'CHAR', 1,
                 'VARCHAR', 1,
                 'VARCHAR2', 1,
                 'DATE', 129,
                 'TIMESTAMP(6)', 129,
                 'FLOAT', 8,
                 'LONG', 126,
                 'RAW', 0,
                 'BINARY_DOUBLE', 8,
                 'BINARY_FLOAT', 7,
                 'NUMBER', DECODE (NVL (data_scale, 0),
                                   0, DECODE (NVL (data_precision, 0),
                                              0, 257,
                                              1, 2,
                                              2, 2,
                                              3, 3,
                                              4, 3,
                                              5, 4,
                                              6, 4,
                                              7, 4,
                                              8, 4,
                                              9, 4,
                                              10, 6,
                                              11, 6,
                                              12, 6,
                                              13, 6,
                                              14, 6,
                                              15, 6,
                                              16, 6,
                                              17, 6,
                                              18, 6,
                                              257
                                             ),
                                   8
                                  ),
                 257
                ) fld_column_type,
         DECODE (data_type,
                 'CHAR', data_length + 1,
                 'VARCHAR', data_length + 1,
                 'VARCHAR2', data_length + 1,
                 'DATE', 20,
                 'TIMESTAMP(6)', 27,
                 'FLOAT', 8,
                 'BINARY_DOUBLE', 8,
                 'BINARY_FLOAT', 4,
                 'LONG', -1,
                 'NUMBER', DECODE (NVL (data_scale, 0),
                                   0, DECODE (NVL (data_precision, 0),
                                              0, 35,
                                              1, 1,
                                              2, 1,
                                              3, 2,
                                              4, 2,
                                              5, 4,
                                              6, 4,
                                              7, 4,
                                              8, 4,
                                              9, 4,
                                              10, 8,
                                              11, 8,
                                              12, 8,
                                              13, 8,
                                              14, 8,
                                              15, 8,
                                              16, 8,
                                              17, 8,
                                              18, 8,
                                              data_precision + 2
                                             ),
                                   8
                                  ),
                 data_length
                ) fld_column_len,
         DECODE (data_type,
                 'CHAR', NULL,
                 'VARCHAR', NULL,
                 'VARCHAR2', NULL,
                 'DATE', 'YYYY-MM-DD HH24:MI:SS',
                 'TIMESTAMP(6)', 'YYYY-MM-DD HH24:MI:SS.FF6',
                 'FLOAT', '%lg',
                 'LONG', NULL,
                 'BINARY_DOUBLE', '%lg',
                 'BINARY_FLOAT', '%g',
                 'NUMBER', DECODE (NVL (data_scale, 0),
                                   0, NULL,
                                      '%'
                                   || TO_CHAR (data_precision + 2)
                                   || '.'
                                   || TO_CHAR (data_scale)
                                   || 'lf'
                                  ),
                 NULL
                ) fld_format,
         k.POSITION
    FROM all_tab_columns c,
         (SELECT table_name, column_name, POSITION
            FROM all_cons_columns
           WHERE owner = :1 AND table_name = :2 AND POSITION IS NOT NULL) k
   WHERE c.table_name = k.table_name(+)
     AND c.column_name = k.column_name(+)
     AND c.owner = :3
     AND c.table_name = :4
ORDER BY c.table_name, c.column_id;

可不是个纸老虎?

"其实模板跟sql语句也差不多,但你写了一个语句,仅仅就是个语句。而模板在程序的许多环节都要用的,是高度可重用代码。"
谁说的?代码可重用性在各种语言都可做到,PLSQL也可模块化,SQL也可做成视图。

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
477#
 楼主| 发表于 2010-2-26 09:39 | 只看该作者
"绑定与值无关,绑定在外边,值仍然随循环变化。"
这可是前所未闻,难道OCI有这功能?典型的过程是解析、绑定、执行。你举出一个最简化的例子,表明一次绑定,修改变量值(但不再次绑定),然后多次执行,数据库会得到不同的数据。

唉!大师,绑定,只是把程序变量与SQL语句里的占位符对应起来,这是基本概念。每次执行都是通过绑定指针找到变量使用最新的值。
在过程语言里,从来都是一次绑定多次使用,见OCIlib说明书,并非只OCIlib如此,所有的过程语言都如此。把绑定移到循环外,再试试。

DAU就是这么用的。这是DAU帮你做的许多工作之一,你不需要理解这些细节就能高效正确的使用系统。封装,很大的部分功能就是封装概念,不需要了解很多概念就可以使用系统。

你说了一大堆,我看很好,但只适用存储过程。如果要用C语言呢?你在怎么重用也只在SQL范围内,我的重用是全过程的,包括数据在函数间的传递,在远过程通信,在文件存取。。。。。。而且一个模板可以多个语句,如那个cube模板还可以用于普通的group,你在应用中可能有许多统计条件,都可以共用。

再说一遍,DAU是为C语言访问数据库服务的。有许多任务不能全靠SQL,是有许多模块协同工作的。如果某些任务存储过程工作得更好,DAU和SDBC也完全支持程序员使用存储过程。SDBC里有ORA_Rpc()调用存储过程和存储函数。见SDBC说明书。


  1. cat fetch_wyf.c
  2. #include "ocilib.h"
  3. #include "sys/time.h"
  4. #include "time.h"
  5. long interval(struct timeval *begtime,struct timeval *endtime)
  6. {
  7. long ret;
  8.         ret=endtime->tv_sec-begtime->tv_sec;
  9.         ret*=1000000;
  10.         ret += endtime->tv_usec - begtime->tv_usec;
  11.         return ret;
  12. }

  13. int main(void)
  14. {
  15.     OCI_Connection *cn;
  16.     OCI_Statement  *st,*trn_st;
  17.     OCI_Resultset  *rs,*trn_rs;
  18.     int rows,ret,cols=0,trn_cols,j,trn_num;
  19.     char stmt[4096],*trn_id;
  20.         char trn_bid[20];

  21.     struct timeval tvpre, tvafter;


  22.     if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
  23.         return EXIT_FAILURE;

  24.     cn  = OCI_ConnectionCreate("ticket", "tbsdba", "tbseasyway", OCI_SESSION_DEFAULT);
  25. gettimeofday(&tvpre, NULL);

  26.     st  = OCI_StatementCreate(cn);
  27.     trn_st  = OCI_StatementCreate(cn);
  28.         OCI_SetFetchSize(st,1500);
  29.         OCI_SetPrefetchMemory(st,512);
  30.         OCI_SetPrefetchSize(st,1269);
  31.    
  32.          OCI_Prepare(st, "select admrp070, admrp019, admrp050, admap007, admcd030, admrp071, admrp072, admrp023, admrp073, admrp074,admrp075, admrp076, admrp009, admrp010, admrp079, admrp080, admcd016, to_char(aebbd001,'YYYY-MM-DD'), to_char(aebbd002,'YYYY-MM-DD'), admrd032 from admrp02  where admcd030 =:trn_id");
  33.     OCI_BindString(st,":trn_id","10157",5);
  34.     OCI_Execute(st);
  35.         printf("stmt is %s\n",OCI_GetSql(st));   
  36. rs = OCI_GetResultset(st);

  37.     cols=OCI_GetColumnCount(rs);

  38.         OCI_Prepare(trn_st, "SELECT ADMRP050 trn_id,ADMAP001 train_type_code,ADMAP011 train_class_code,ADMOR008,to_char(AEBBD001,'YYYY-MM-DD') beg_date,to_char(ADMRP066,'YYYY-MM-DD') end_date,ADMRP051 stn_num,ADMRP026 train_code,ADMRP027 start_time,ADMRP052 start_trn,ADMRP053 start_stn_name,ADMRP054 end_trn,ADMRP055 end_stn_name,ADMRP056,ADMRP057,ADMRP058 items,ADMRP067 flag,ADMRP059 cycle,ADMRP060 seat_types,ADMRP061,ADMRP062,ADMAP050 note,ADMRP063 days FROM TBSDBA.ADMRP03 WHERE ADMRP050=:trn_id");
  39. //trn_st在这里绑定
  40.         ret=OCI_BindString(trn_st,":trn_id",trn_bid,12);
  41.         if(ret != TRUE) printf("bind error %d\n",ret);
  42.    
  43.         trn_num=0;
  44.     for (rows=0;OCI_FetchNext(rs);rows++) {   
  45.         int i=0;
  46.         for( i=0;i<cols; i++) {
  47.                 if(i==2) {
  48.                         strcpy(trn_bid,(char *)OCI_GetString(rs, i+1));
  49.                 }
  50.             else OCI_GetString(rs, i+1);
  51.           }
  52. //trn_st是在循环外绑定的。
  53.         ret=OCI_Execute(trn_st);
  54.         if(ret != TRUE ) continue;

  55.         trn_num++;
  56.         trn_rs = OCI_GetResultset(trn_st);
  57.         trn_cols=OCI_GetColumnCount(trn_rs);
  58.         while (OCI_FetchNext(trn_rs)) {   

  59.                 for( j=0;j<trn_cols; j++) {
  60.                       OCI_GetString(trn_rs, j+1);
  61.                 }
  62.         }
  63. //      OCI_BindFreeAll(trn_st);

  64. //      OCI_ReleaseResultsets(trn_st);
  65.      }
  66.         OCI_StatementFree(st);
  67.         OCI_StatementFree(trn_st);
  68.     printf("%d row(s) fetched,trn_cols=%d,trn_num=%d\n",OCI_GetRowCount(rs),trn_cols,trn_num);

  69.     gettimeofday(&tvafter, NULL);
  70.     OCI_Cleanup();

  71.     printf("total time=%ld usec\n",interval(&tvpre,&tvafter));

  72.     return EXIT_SUCCESS;
  73. }

复制代码

[ 本帖最后由 yulihua49 于 2010-2-26 10:13 编辑 ]

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
478#
发表于 2010-2-26 23:21 | 只看该作者
哦,OCI是绑定地址的,这个我确实不懂。DBMS_SQL只能绑定值而PLSQL里面也没有指针的概念。

"你说了一大堆,我看很好,但只适用存储过程。如果要用C语言呢?你在怎么重用也只在SQL范围内,我的重用是全过程的,包括数据在函数间的传递,在远过程通信,在文件存取。。。。。。而且一个模板可以多个语句,如那个cube模板还可以用于普通的group,你在应用中可能有许多统计条件,都可以共用。"
如果用了存储过程,那么获取数据的方法就是可重用的,即你调用同一个存储过程。至于数据本身怎么被重复利用,这已经脱离数据库了,爱怎么做就怎么做。
"那个cube模板还可以用于普通的group"
实际应用中不会有这样的例子,有也是极其罕见。你意思是说SELECT部分可被很多SQL共享,这些SQL的FROM, WHERE等可以不同,这个根据我经验,没什么实用意义。不同的SQL输出结构往往也不同。即使有这样的例子我们也轻易用动态SQL解决。

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
479#
 楼主| 发表于 2010-2-27 10:15 | 只看该作者
原帖由 newkid 于 2010-2-26 23:21 发表
哦,OCI是绑定地址的,这个我确实不懂。DBMS_SQL只能绑定值而PLSQL里面也没有指针的概念。

"你说了一大堆,我看很好,但只适用存储过程。如果要用C语言呢?你在怎么重用也只在SQL范围内,我的重用是全过程的,包括数据在函数间的传递,在远过程通信,在文件存取。。。。。。而且一个模板可以多个语句,如那个cube模板还可以用于普通的group,你在应用中可能有许多统计条件,都可以共用。"
如果用了存储过程,那么获取数据的方法就是可重用的,即你调用同一个存储过程。至于数据本身怎么被重复利用,这已经脱离数据库了,爱怎么做就怎么做。
"那个cube模板还可以用于普通的group"
实际应用中不会有这样的例子,有也是极其罕见。你意思是说SELECT部分可被很多SQL共享,这些SQL的FROM, WHERE等可以不同,这个根据我经验,没什么实用意义。不同的SQL输出结构往往也不同。即使有这样的例子我们也轻易用动态SQL解决。

很多语言没有指针的概念,但内部机制含有指针操作,如JAVA,其实处处皆指针。你不妨试一下,循环外绑定,告结果。

在单表操作时,模板可以在所有操作中共享。
动态SQL当然也是一个办法,写SDBC之初也考虑了动态SQL,还是有些问题难于处理。

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
480#
发表于 2010-2-28 01:15 | 只看该作者
试过了,不是传址的。

declare
   v_sql varchar2(200);
   l_theCursor   integer;
   l_status      integer;
   I NUMBER;
begin

  v_sql:='INSERT INTO T VALUES (:c1,:c2,:c3,:amount)';  
   
  l_theCursor := dbms_sql.open_cursor;
  
  dbms_sql.parse( c => l_theCursor,
                  statement => v_sql,
                  language_flag => dbms_sql.native
                 );

  I :=1;
        dbms_sql.bind_variable( c => l_theCursor,
                                name => ':c1',
                               value => i
                              );   
        dbms_sql.bind_variable( c => l_theCursor,
                                name => ':c2',
                               value => i
                              );   
        dbms_sql.bind_variable( c => l_theCursor,
                                name => ':c3',
                               value => i
                              );   
        dbms_sql.bind_variable( c => l_theCursor,
                                name => ':amount',
                               value => i
                              );   
        l_status := dbms_sql.execute(l_theCursor);
  I:=2;
        l_status := dbms_sql.execute(l_theCursor);
  
  dbms_sql.close_cursor( c => l_theCursor );

end;
/
PL/SQL procedure successfully completed.

Elapsed: 00:00:00.12
SQL> select * from t;

        C1         C2         C3     AMOUNT
---------- ---------- ---------- ----------
         1          1          1          1
         1          1          1          1

Elapsed: 00:00:00.02

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表