小弟使用OTL函数,动态拼凑SQL查询oracle数据库数据问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小弟使用OTL函数,动态拼凑SQL查询oracle数据库数据问题相关的知识,希望对你有一定的参考价值。

使用的是如下代码几种方式,都不能运行通过
一:
typeName = _T("DataPoint");
Location = _T("(2, 3, 4, 5)");
otl_stream i(500000, // buffer size can be > 1
"select e.pkey, e.name from entity_v e where e.typename = :v_name<char[31]> and e.deleted = 0 and e.locationkey in:v_location<char[31]>",
db // connect object
);

i<<typeName;
i<<Location;

错误提示:无效的数字
应该是Location变量绑定有问题
第二种:
typeName = _T("DataPoint");
Location = _T("e.locationkey=2");
otl_stream i(500000, // buffer size can be > 1
"select e.pkey, e.name from entity_v e where e.typename = :v_name<char[31]> and e.deleted = 0 and e.locationkey in:v_location<char[31]>",
db // connect object
);

i<<typeName;
i<<Location;
错误提示:无效的关系运算符
将=写在sql语句中就可以通过,写在Location变量中就无法通过。

官方例子中只能找到简单的绑定变量的例子,如e.locationkey= :var<int>等方式。
如果我需要的是动态拼凑sql语句,比如我的查询条件是e.locationkey=2 or e.locationkey=3 or e.locationkey=4,或者是 e.locationkey in(2,3,4)这种动态随机的sql语句的话,我简单的将这段字符串通过:var<char[31]>等字符变量绑定在otl_stream 的构造函数的sql语句中,就会报错。目前情况是它貌似只能接受简单的已经构造好SQL语句的字符串,构造otl_stream 时需要sql语句检查,当时变量还没绑定,所以大概是SQL语义不正常吧,就报了上述那些错误。

请教各位大大们,如果要实现上面那个动态生成多条件sql语句查询,我该如何写。非常感谢!!!
问题解决,至此关闭。
多谢大家关注!

参考技术A OTL介绍:

  OTL 是Oracle, Odbc and DB2-CLI Template Library 的缩写,是一个C++操控关系数据库的模板库,最新版本4.0.104,参见http://otl.sourceforge.net/,下载地址http://otl.sourceforge.net/otlv4_h.zip。

  优点:a. 跨平台

  b. 运行效率高,与C语言直接调用API相当

  c. 开发效率高,起码比ADO.net使用起来更简单,更简洁

  d. 部署容易,不需要ADO组件,不需要.net framework 等

  缺点:

  a. 只有C++才可以使用她

  b. 说明以及范例不足(暂时性的)

  总的说来,对于C++程序员而言,使用OTL操作关系数据库是最好的选择,其网站上有很多的范例,本人在这里对使用OTL调用Oracle的存储函数(存储函数比存储过程多个返回值)作一个示范,而其他的比如查询、更新、存储过程等就太简单了,直接看otl.sourceforge.net的范例 。

  Oracle 存储函数 TEST 代码:

  ( a In Integer, b Out Integer, c in out Integer, d In Long ) Return Long

  is

  begin

  b := a;

  c := 2 * c;

  Return( '<' || d || '>' );

  end;

  说明:Oracle中的long不是C/C++中的长整型,而是varchar_long,对应着OTL中的otl_long_string,这是一种很复杂的类型,本人就用它来举例。

  C++调用TEST的代码:

  #include <string>

  #include <iostream>

  //#define OTL_ORA9I // 使用这个宏就表示使用Oracle9i的API,而不是ODBC API

  #define OTL_ODBC // 使用这个宏就表示使用通用的ODBC API

  #include "otlv4.h"

  using namespace std;

  void main( void )

  

  otl_connect::otl_initialize();

  try

  otl_connect db;

  db.rlogon( "Driver=Microsoft ODBC for Oracle;Server=ZZZ;Uid=XXX;Pwd=YYY;" );

  // db.set_max_long_size(?); 如果varchar_long长度非常长,超过默认值的话,你需要这一句

  otl_stream o( 1, " :E<varchar_long,out> = call TEST( :A<int,in>,:B<int,out>,:C<int,inout>,:D<varchar_long,in&g t; ) ", db );

  o.set_commit(0);

  int a = 1;

  int b = 0;

  int c = 2;

  otl_long_string d( "abc", 0, 3 );

  otl_long_string e;

  o << a << c << d;

  o >> e >> b >> c;

  cout << "b = " << b << 'n';

  cout << "c = " << c << 'n';

  cout << "e = " << e.v << 'n';

  //db.commit();

  db.logoff();

  

  catch( otl_exception& p )

  cerr << p.msg << "n"

  << p.stm_text << "n"

  << p.sqlstate << "n"

  << p.var_info << "n"

  << endl;

  

  

  说明:" :E<varchar_long,out> = call TEST( :A<int,in>,:B<int,out>,:C<int,inout>,:D<varchar_long,in&g t; ) "这一句中的A、B、C、D、E就是一个名字,随各人喜欢可写成其他任何名称。但这个格式需要注意,它不是

  " call :Name1<int,out> := function( Name2<int,in> "

  也不是

  " call :Name1<int,out> \:= function( Name2<int,in> "

  而是

  " :Name1<int,out> = call function( Name2<int,in> "

  这一点和otl.sourceforge.net上的说明不一样。

oracle动态sql,查询中查找使用过的表

【中文标题】oracle动态sql,查询中查找使用过的表【英文标题】:Oracle dynamic sql, find used tables in query 【发布时间】:2019-10-22 14:59:30 【问题描述】:

有没有办法在 Oracle 动态 SQL 中找到已用表的列表。我需要设置一些表格的使用限制。

动态查询文本示例:

select *
  from Table1 T1
  join Table2 T2
    on T1.Col1 = T2.Col1
 where exists (select 1
          from Table3 T3
         where T1.Col2 = T3.Col2)

结果应该是:[Table1, Table2, Table3]。有什么想法吗?

【问题讨论】:

我认为没有任何方法可以做到这一点。您也许可以解析解释计划调用的结果 将查询放在一个字符串中,并使用正则表达式来查找 from 和 join 关键字之后的表?当您过滤掉TABLE ACCESS 所在的行时,解释输出的相同想法.. 感谢所有帮助解决此问题的人。我计划为我的软件添加机会,让用户可以通过自己编写 SQL Query 来获取报告。但问题是我不能允许使用所有表格和所有功能。我想,我应该找到另一种方法来解决这个问题 【参考方案1】:

“有没有办法在 Oracle 动态 SQL 中找到已用表的列表”。

没有。也就是说,没有铸铁和直截了当的方法。动态 SQL 的后果之一是影响分析的难度增加。

确实,您也许能够在源代码中找到一些嵌入在文字字符串中的表名。

select *
from user_source
where lower(text) like '%table1%'
or  lower(text) like '%table2%'
or  lower(text) like '%table3%'

显然,您需要清除输出以隔离表名,并可能处理table17table23 上的误报。

但是,动态 SQL 通常会处理名称在运行时作为参数字符串传递或从数据字典中查询的表。你不太可能抓住所有这些。显然,这个差距的大小取决于你如何使用动态 SQL:也许你会没事的。

如果您的组织为 Tuning 和 Diagnostics 包付费,您可以使用 ASH 来查找已执行的 SQL ID,您可以对其进行解析以找到相关的表,幸运的话还可以预测生成和执行 SQL 的代码。

【讨论】:

【参考方案2】:

将您的动态 SQL 字符串放入 SQL SELECT 语句中,如下所示,以提取字符串中包含的表名:

with t(str) as
(
 select 'select *
  from Table1 T1
  join Table2 T2
    on T1.Col1 = T2.Col1
 where exists (select 1
          from Table3 T3
         where T1.Col2 = T3.Col2)' from dual
), t2 as
(
  select level as row_num, regexp_substr(to_char(t.str),'^.*$',1,level,'m') as str
    from t
   connect by level <= length (to_char(t.str)) 
                     - length (replace (to_char(t.str), chr (10))) + 1 
), t3 as
(
select regexp_substr(
           regexp_substr(str,'From[[:space:]].*[[:space:]]',1,1,'i'),
                        '[^ ]+',1,2) as x,
       regexp_substr(
           regexp_substr(str,'Join[[:space:]].*[[:space:]]',1,1,'i'),
                        '[^ ]+',1,2) as y
  from t2 
)
select coalesce(x,y) as "Tables"
  from t3
 where coalesce(x,y) is not null;

Tables
-------
Table1
Table2
Table3 

Demo

【讨论】:

【参考方案3】:

可以使用DBMS_UTILITY.EXPAND_SQL_TEXT、临时视图和查询DBA_DEPENDENCIES生成SQL语句使用的表列表。

DBMS_UTILITY.EXPAND_SQL_TEXT 负责查找视图引用的表。临时视图和DBA_DEPENDENCIES 然后生成扩展 SQL 语句中使用的所有表的列表。

功能

create or replace function get_dependent_tables_from_sql(p_sql varchar2)
return sys.odcivarchar2list authid current_user is
    v_expanded_sql clob;
    v_tables sys.odcivarchar2list := sys.odcivarchar2list();
    pragma autonomous_transaction;
begin
    --Expand the SQL, which will go through all the recursive dependencies.
    dbms_utility.expand_sql_text
    (
        input_sql_text  => p_sql,
        output_sql_text => v_expanded_sql
    );

    --Create a view with the expanded SQL.
    execute immediate
    '
        create or replace view temp_view_for_dependencies as
        select count(*) the_count
        from
        (
        '||v_expanded_sql||'
        )
    ';

    --Find dependencies.
    --(Use execute immediate to simplify compilation privileges.)
    execute immediate
    q'[
        select distinct referenced_owner||'.'||referenced_name
        from dba_dependencies
        where name = 'TEMP_VIEW_FOR_DEPENDENCIES'
            and owner = user
            and referenced_type = 'TABLE'
    ]'
    bulk collect into v_tables;

    return v_tables;
end get_dependent_tables_from_sql;
/

示例架构

create table table1(col1 number, col2 number);
create table table2(col1 number, col2 number);
create table table3(col1 number, col2 number);
create table table4(col1 number, col2 number);
create table table5(col1 number, col2 number);
create or replace view view1 as select 1 a from dual;

调用函数

select column_value table_name
from table(get_dependent_tables_from_sql(q'[
        select *
        from table1 t1
        --ANSI joins
        join table2 t2
            on t1.col1 = t2.col1
        where exists
        (
            select 1
            --Oracle style joins, views.
            from table3 t3, table4, view1
            where t1.col2 = t3.col2
        )
        --A table that won't be in execution plan.
        and exists (select 1 from table5 where 1 = 2)   
    ]'))
order by 1;

TABLE_NAME
----------
JHELLER.TABLE1
JHELLER.TABLE2
JHELLER.TABLE3
JHELLER.TABLE4
JHELLER.TABLE5
SYS.DUAL

关于其他解决方案的警告

小心涉及自定义 SQL 解析的解决方案。这是看起来非常容易的问题之一。您可以构建一个 98% 的时间都有效的正则表达式,但实际上不可能构建一个 100% 的时间有效的正则表达式。

谨慎使用执行计划解决方案。将执行计划对象追溯到表并非易事,就像只使用索引一样。并且某些表可以在查询中使用,但由于连接消除而被排除在执行计划之外。

【讨论】:

以上是关于小弟使用OTL函数,动态拼凑SQL查询oracle数据库数据问题的主要内容,如果未能解决你的问题,请参考以下文章

otl格式文档怎么下载

OTL翻译 -- otl_stream流相关绑定变量

用otl写的oracle取数工具,执行传入在查询语句,把结果输出到文件

OTL调用存储过程/函数及注意事项

OTL翻译 -- otl_stream类

oracle在sql查询中没有函数调用的索引