【问题标题】:To Dynamic SQL or Not是否使用动态 SQL
【发布时间】: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 :该函数实际上返回一个布尔值,并且工作正常。我只是想知道安全影响和最佳实践。谢谢!

标签: oracle plsql


【解决方案1】:

至于最佳实践,在这些情况下,建议使用sys.dbms_assert 包。

FUNCTION ConcurrencyCheck(
    pi_orarowscn_in             IN NUMBER,
    pi_table_name               IN VARCHAR2,
    pi_column_name              IN VARCHAR2,
    pi_id                       IN NUMBER
)
RETURN BOOLEAN IS
    ln_orarowscn_current NUMBER := 0;
    lv_sql VARCHAR2(300) := '';
BEGIN
    lv_sql := '
        select X.ora_rowscn
        from '||sys.dbms_assert.sql_object_name(pi_table_name)||' X
        where X.'||sys.dbms_assert.simple_sql_name(pi_column_name)||' = :pi_id
    ';
    execute immediate lv_sql
        into ln_orarowscn_current
        using in pi_id;

    return ln_orarowscn_current <> pi_orarowscn_in;
END ConcurrencyCheck;

注意:如果我在你的位置上,我会给自己一个最初的艰难时期,为一表一检查函数包实现元数据驱动的代码生成器正如您可能已经猜到的那样,这将是静态 PL/SQL 代码——为您提供所有这些不错的编译时语法/语义检查。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 2011-11-28
    • 2011-04-18
    • 2011-03-26
    • 1970-01-01
    相关资源
    最近更新 更多