强制数据库将字符串视为SQL
有没有办法强迫我的dbms(oracle)将字符串视为SQL代码 例如,在查询强制数据库将字符串视为SQL,sql,oracle,Sql,Oracle,有没有办法强迫我的dbms(oracle)将字符串视为SQL代码 例如,在查询中选择num from numbers,其中num在'5和7'之间,我希望'5和7'被计算为SQL 编辑: 这就是我的查询当前的样子: select num from tbl_1 where num between (select min(num) from tbl_2) and (select max(num) from tbl_2);
中选择num from numbers,其中num在'5和7'之间
,我希望'5和7'
被计算为SQL
编辑:
这就是我的查询当前的样子:
select num from tbl_1
where num between (select min(num) from tbl_2)
and
(select max(num) from tbl_2);
我想知道是否有一种方法可以只使用一个子查询来实现这一点。我不认为Oracle可以做您想做的事情,但您可以编写
select num
from numbers
where num between &1 and &2;
这将导致Oracle提示您输入替换值,尽管这在您的上下文中可能不起作用。你到底想干什么
根据您的评论,我假设您有一个列名范围存储像“1和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.
;
这里的基本思想是在子查询中使用一些字符串操作来查找字符串中范围的两个起始值和结束值。我不确定这是否会准确运行,但我希望想法是明确的?两种方式:
不首选1) 动态SQL:创建一个字符串,将
执行的所有内容连接起来。注意,这很容易被注入
首选
2) 分析两个参数5和7的输入字符串,位于分隔的“and”的相对侧,然后将它们用作
SELECT... WHERE NUM BETWEEN @pMin AND @pMax
这通常是一个非常糟糕的主意。除非你有很好的理由这么做。将字符串作为查询的一部分传递到数据库是一种有保证的方式,最终会导致注入漏洞或陷坑的裂口,如果后来出现的程序员出错,这可能会真正扰乱数据库
如果您想要动态查询,请查看专门为此设计的编程结构,如JPA中的条件查询。不要。只是不要这样做。你真的想把更多的怪物带到这个世界上吗?没有办法将字符串转换为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
中放入10000个连续值,在tbl_1
中放入100000个连续值,并将每个查询运行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;
/
创建表tbl_1(编号)
/
创建表tbl_2(数字编号)
/
插入tbl_1
选择级别
来自双重
按级别连接我想从来自同一表中同一列的两个值中构造一个范围。因此,与其有两个(几乎相同的)子查询,我想也许我可以从单个子查询中以字符串形式返回范围,这些子查询将非常便宜。10000行和100000行是一个相当小的表:)@a_horse_和_no_name:我愿意投入的时间和资源是有限的。我确实提供了代码,如果有人想用更大的样本来尝试。对不起,我不是有意冒犯你。我只是觉得这个数量的行很可能是在一次表扫描后缓存的。@a_horse_和_no_name:没有冒犯,你可能是对的。但是,我仍然认为这两个查询之间的性能差异是最小的(如果有明显的索引,甚至更小)。