强制数据库将字符串视为SQL

时间:2011-10-06 20:23:55

标签: sql oracle

有没有办法强制我的dbms(oracle)将字符串视为SQL代码?

例如,在查询select num from numbers where num between '5 and 7'中,我希望'5 and 7'被评估为SQL。

编辑:

这是我目前的查询:

select num from tbl_1 
where num between (select min(num) from tbl_2) 
                    and 
                  (select max(num) from tbl_2);

我想知道是否只有一个子查询可以做到这一点。

5 个答案:

答案 0 :(得分:5)

<强>别。只是。不要。你真的想把更多的怪物such as this带入这个世界吗?

答案 1 :(得分:2)

无法将字符串转换为SQL中的条件(有充分理由)。

但是,如果您已经设置了减少子查询的数量,则以下查询等同于您的查询。

SELECT num
FROM        tbl_1 t1
       JOIN (SELECT MIN(num) min_num, MAX(num) max_num FROM tbl_2) t2
         ON t1.num BETWEEN t2.min_num AND t2.max_num

然而,即使tbl_2.num没有被编入索引,所获得的性能提升也是如此之小,以至于不值得丢失可读性。我在tbl_2中放置了10,000个连续值,在tbl_1中放置了100,000个连续值,并将每个查询运行了1000次。总执行时间的差异小于5毫秒(在误差范围内)。

我的测试:

CREATE TABLE tbl_1 (num NUMBER)
/

CREATE TABLE tbl_2 (num NUMBER)
/

INSERT INTO tbl_1
   SELECT     LEVEL
   FROM       DUAL
   CONNECT BY LEVEL <= 100000
   /

INSERT INTO tbl_2
   SELECT     LEVEL
   FROM       DUAL
   CONNECT BY LEVEL <= 10000
   /

ANALYZE TABLE tbl_1 COMPUTE STATISTICS
/
ANALYZE TABLE tbl_2 COMPUTE STATISTICS
/

DECLARE
   v_repititions CONSTANT PLS_INTEGER := 1000;

   CURSOR cur_old IS
      SELECT num
      FROM   tbl_1
      WHERE  num BETWEEN (SELECT MIN(num) FROM tbl_2) 
                     AND (SELECT MAX(num) FROM tbl_2);

   r_old         cur_old%ROWTYPE;

   CURSOR cur_new IS
      SELECT num
      FROM        tbl_1 t1
             JOIN (SELECT MIN(num) min_num, MAX(num) max_num FROM tbl_2) t2
               ON t1.num BETWEEN t2.min_num AND t2.max_num;

   r_new         cur_new%ROWTYPE;
   i             PLS_INTEGER;
   v_start_time  timestamp;
   v_end_time    timestamp;
BEGIN
   v_start_time   := SYSTIMESTAMP;

   FOR i IN 1 .. v_repititions LOOP
      FOR r_old IN cur_old LOOP
         NULL;
      END LOOP;
   END LOOP;

   v_end_time     := SYSTIMESTAMP;
   DBMS_OUTPUT.put_line('Old Query: ' || TO_CHAR(v_end_time - v_start_time));
   v_start_time   := SYSTIMESTAMP;

   FOR i IN 1 .. v_repititions LOOP
      FOR r_new IN cur_new LOOP
         NULL;
      END LOOP;
   END LOOP;

   v_end_time     := SYSTIMESTAMP;
   DBMS_OUTPUT.put_line('New Query: ' || TO_CHAR(v_end_time - v_start_time));
END;
/

答案 2 :(得分:0)

我认为Oracle不能做你想做的事,但你可以写

select num
from numbers
where num between &1 and &2;

这将导致Oracle提示您输入替换值,尽管这可能不适用于您的上下文。你究竟想做什么?


根据您的评论,我假设您有一个列名称range_vals存储值'1 AND 2'

select num
from numbers,
  (select instr(range_vals,' ',1,1) as low_pos, instr(range_vals,' ',2,1) as hi_pos, range_vals
  from table_of_range_vals
  where [some condition]) range_subq
where numbers.num between to_number(substr(range_subq.range_vals,1,low_pos)) --parse out the low end of the range
                  and     to_number(substr(range_subq.range_vals,hi_pos,length(range_subq.range_vals))) --parse out the high-end of the range.
;

这里的基本思想是在子查询中使用一些字符串操作来查找字符串中范围的两个起始值和结束值。我不确定这是否会完全正确,但我希望这个想法很明确?

答案 3 :(得分:0)

两种方式:

不首选
1)动态SQL:创建一个串联EXECUTE所有内容的字符串。请注意,这很容易受到注射

<强>优选
2)解析两个参数5和7的输入字符串,在分隔符“和”的两侧,然后将它们用作参数

 SELECT... WHERE NUM BETWEEN @pMin AND @pMax

答案 4 :(得分:0)

这通常是一个非常糟糕的主意。除非你有一个非常好的理由这样做。将字符串作为查询的一部分传递到数据库是一种保证的方式,最终会导致注入漏洞或陷阱的大量陷阱,如果稍后出现的程序员发生错误,可能会使数据库陷入困境。 / p>

如果您想要动态查询,请查看旨在执行该操作的编程结构,例如JPA中的Criteria查询。