【发布时间】:2017-09-26 19:58:28
【问题描述】:
在进行更新时,我们希望对 ORA_ROWSCN (Oracle db BTW) 进行并发检查。所以我正在考虑创建一个函数,在其中传入你拥有的 ora_rowscn、表名、列名和一个 ID。该函数将检查是否会根据您传入的表、列和 id 执行选择语句,如果返回的 ora_rowscn 与您传入的不同,则返回 true 或 false 是否相同。
我对传入的 table_name 和 column_name 进行有效性检查,以确保它们首先存在。
FUNCTION ConcurrencyCheck (
pi_orarowscn_in IN NUMBER,
pi_table_name IN VARCHAR2,
pi_column_name IN VARCHAR2,
pi_id IN NUMBER
)
RETURN BOOLEAN IS
r_data_out_of_date BOOLEAN := false;
ln_orarowscn_current NUMBER := 0;
lv_sql VARCHAR2(300) := '';
lv_column VARCHAR(20) := '';
lv_table VARCHAR(20) := '';
BEGIN
SELECT table_name INTO lv_table from ALL_TABLES WHERE TABLE_NAME = pi_table_name;
IF lv_table = '' THEN
RAISE NO_DATA_FOUND;
ELSE
SELECT column_name INTO lv_column from USER_TAB_COLUMNS WHERE TABLE_NAME = pi_table_name AND COLUMN_NAME = pi_column_name;
IF lv_column = '' THEN
RAISE NO_DATA_FOUND;
ELSE
lv_sql := 'select ORA_ROWSCN from ' || pi_table_name || ' where ' || pi_column_name || ' = ' || pi_id || '';
EXECUTE IMMEDIATE lv_sql INTO ln_orarowscn_current;
IF ln_orarowscn_current <> pi_orarowscn_in THEN
r_data_out_of_date := true;
END IF;
END IF;
END IF;
RETURN r_data_out_of_date;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE;
WHEN OTHERS THEN
RAISE;
END ConcurrencyCheck;
我不喜欢那里的动态 SQL。我更希望(没有动态 SQL,但是...)如下所示:
lv_sql := 'select ORA_ROWSCN from :table_name where :column_name = :id';
EXECUTE IMMEDIATE lv_sql INTO ln_orarowscn_current USING pi_table_name, pi_column_name, pi_id;
但我不断收到 SQL 错误,提示表错误
另一种解决方案是为所有表创建一个子函数,该函数将为每个表返回 ORA_ROWSCN,并在主函数中调用一个 IF ELSE。
我在这里寻找最佳实践。这是一个可以接受动态 SQL 的时代吗?还是我应该走“长”路线并为每个表创建大量函数/程序?
谢谢!
【问题讨论】:
-
不幸的是绑定变量不能用于表名或列名,只能用于数据,你别无选择只能使用动态sql
-
感谢您的回复。那是我想的。您认为最好使用动态 SQL 还是使用一堆由 main 函数调用的过程?
-
我不会创建程序,因为您的代码会更难阅读和理解。但我认为还有改进的方法。例如,为什么不一次检查 table_name 和 column_name 的存在?
-
函数思路也不错,可能返回游标或者变数组?
-
Cyrille :是的,当然,这应该只是一张支票。感谢您的输入。 Ted :该函数实际上返回一个布尔值,并且工作正常。我只是想知道安全影响和最佳实践。谢谢!