我想要捕获没有WHERE子句的更新语句。如果用户更新table1,则必须有where子句。
模式1:格式错误
UPDATE table1 SET column1 = 'Test'
模式1:格式正确
UPDATE table1 SET column1 = 'Test' WHERE ... col1 = ...
而......意味着介于两者之间。
模式2:格式错误
UPDATE table1 SET column1 = (SELECT columnA FROM table2 WHERE rownum = 1)
模式2:格式正确
UPDATE table1 SET column1 = (SELECT columnA FROM table2 WHERE rownum = 1) WHERE ... col1 = ...
由于内部查询调用table2,因此WHERE子句不是必需的。
模式3:格式错误
UPDATE table1 SET column1 = (SELECT column2 FROM table1 WHERE rownum = 1)
模式3:格式正确
UPDATE table1 SET column1 = (SELECT column2 FROM table1 WHERE rownum = 1 WHERE ... col1 = ...) WHERE ... col1 = ...
模式4:正确的格式;不需要where子句
UPDATE table2 SET columnA = (SELECT columnB FROM table3 WHERE rownum = 1)
我打算编写一个程序来捕获错误的更新格式。但是,我必须首先弄清楚regexp_like语法。
我尝试了很多方法,但无法真正抓住每一种模式。以下是我正在尝试的模板查询:
WITH tbl AS
(
SELECT 'UPDATE table1 SET column1 = 999 WHERE col1 = 111' as col1 FROM DUAL
UNION
SELECT 'UPDATE table1 SET column1 = (SELECT columnA FROM table2 WHERE rownum = 1) WHERE col1 = 111' FROM DUAL
UNION
SELECT 'UPDATE table1 SET column1 = (SELECT column2 FROM table1 WHERE rownum = 1 WHERE col1 = 111) WHERE col1 = 111' FROM DUAL
UNION
SELECT 'UPDATE table2 SET columnA = (SELECT columnB FROM table3 WHERE rownum = 1)' FROM DUAL
)
SELECT col1, 'pattern 1' FROM tbl WHERE REGEXP_LIKE (upper(col1), 'UPDATE.*TABLE1.*SET.*WHERE.*col1.*=.*')
UNION ALL
SELECT col1, 'pattern 2' FROM tbl WHERE REGEXP_LIKE (upper(col1), '') -- ???
UNION ALL
SELECT col1, 'pattern 3' FROM tbl WHERE REGEXP_LIKE (upper(col1), '') -- ???
UNION ALL
SELECT col1, 'pattern 4' FROM tbl WHERE REGEXP_LIKE (upper(col1), '') -- ???
假设我只是想搜索一个字符串。该查询将作为字符串参数传递给存储过程。
我正在使用Oracle SQL Developer。
感谢任何帮助。
答案 0 :(得分:0)
您可以使用以下内容:
^UPDATE\s*table1\s*SET\s*\w+\s*=\s*(.+?)\s*WHERE[^\)]*$|^UPDATE\s*((?!table1).)*$
table1
where
子句匹配更新语句"在table1
注意:如果与g,i and m
修饰符一起使用,则效果最佳。
答案 1 :(得分:0)
如果您的系统是开放式的,用户可以传入任意选择或更新语句,那么捕获缺少的where子句并不能真正解决真正的问题。但假设您必须拥有此功能,那么在执行它之前,可能会在每个语句上运行解释计划,然后检查成本或路径选项。例如:
EXPLAIN PLAN
SET STATEMENT_ID = 'BAD1' FOR
SELECT * from big_table;
输出:
STATEMENT_ID OPERATION OPTIONS OPTIMIZER COST CARDINALITY
BAD1 SELECT STATEMENT ALL_ROWS 344119 40523300
BAD1 TABLE ACCESS FULL ANALYZED 344119 40523300
" Good"语句(使用索引)可能如下所示:
EXPLAIN PLAN
SET STATEMENT_ID = 'GOOD1' FOR
SELECT * from big_table where colA=123;
输出:
STATEMENT_ID OPERATION OPTIONS OPTIMIZER COST CARDINALITY
GOOD1 SELECT STATEMENT ALL_ROWS 3 1
GOOD1 TABLE ACCESS BY INDEX ROWID ANALYZED 3 1
GOOD1 INDEX UNIQUE SCAN ANALYZED 2 1
请注意表格访问权限的差异,高成本与低成本的索引扫描。
无论如何,也不完美,但可能比一些正则表达式更好。
答案 2 :(得分:0)
我认为你不应该这样做。即使您信任您的用户,也无法区分“好”查询和“错误”查询(尤其是正则表达式)。 让用户直接操作数据库可能会破坏系统的商业规则(错误或自愿)
如果可以限制用例,可能更安全的替代方法是让用户从列表中选择参数化更新查询,并输入参数。我觉得你不能或不想给他们一个合适的用户界面。