验证 Oracle 列名

pOr*_*inG 4 oracle oracle11g

在一种情况下,我们正在动态地动态创建 sql 到create临时表。table_name 没有问题,因为它是由我们决定的,但是列名是由我们无法控制的来源提供的。

通常我们会使用以下查询检查列名:

select  ..
where NOT REGEXP_LIKE (Column_Name_String,'^([a-zA-Z])[a-zA-Z0-9_]*$') 
OR Column_Name_String is NULL
OR Length(Column_Name_String) > 30
Run Code Online (Sandbox Code Playgroud)

但是,是否有任何内置功能可以进行更广泛的检查。也欢迎对上述查询的任何输入。

提前致谢。


基于以下答案的最终查询:

select  ..
where NOT REGEXP_LIKE (Column_Name_String,'^([a-zA-Z])[a-zA-Z0-9_]{0,29}$') 
OR Column_Name_String is NULL
OR Upper(Column_Name_String) in (select Upper(RESERVED_WORDS.Keyword) from V$RESERVED_WORDS RESERVED_WORDS)
Run Code Online (Sandbox Code Playgroud)

特别不满意列名中像 $ 这样的字符,因此也不会使用..

dbms_assert.simple_sql_name('VALID_NAME')
Run Code Online (Sandbox Code Playgroud)

相反,使用正则表达式,我可以决定允许使用自己的一组字符。

Tim*_*sen 5

此答案不一定提供性能或逻辑改进,但您实际上可以使用单个正则表达式验证列名:

SELECT ...
WHERE NOT
    REGEXP_LIKE (COALESCE(Column_Name_String, ''), '^([a-zA-Z])[a-zA-Z0-9_]{0,29}$')
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为:

  • 它使用相同的模式来匹配列,即以字母开头,然后仅使用字母数字字符和下划线
  • NULL 列名映射到空字符串,这使正则表达式失败
  • 我们使用长度量词{0,29}直接在正则表达式中检查列长度


APC*_*APC 4

“是否有任何内置功能可以进行更广泛的检查。”

Oracle有这个DBMS_ASSERT.SIMPLE_SQL_NAME()功能。如果符合 Oracle 命名规则,则返回传递的名称...

 select dbms_assert.simple_sql_name('VALID_NAME') from dual;
Run Code Online (Sandbox Code Playgroud)

ORA-44003...如果名称无效则抛出。

如果名称用双引号引起来,则有效名称允许使用任何字符(糟糕,但创建“动态临时表”也是如此)。此外,该函数不会检查名称的长度,因此您仍然需要自己验证。

在文档中了解更多信息。

这里还有一个 SQL Fiddle


“不可能创建带有注释列的表,因为它的标识符无效”

有道理。DBMS_ASSERT主要是为了防止SQL注入。因此它验证一个值是否符合 Oracle 的命名规则,而不是该值是一个有效的 Oracle 名称。要捕获类似的内容,您可能还需要根据V$RESERVED_WORDScomment检查该值。由于这是一个视图,默认情况下不会授予对其选择;如果您无权访问,则需要请友好的 DBA 提供帮助。where reserved != 'Y'V$

“为了验证列名称,我相信我应该检查整个列表”

由你决定。区别在于某些关键字可以合法地用作标识符。例如,当 Oracle 版本 8 引入对象关系内容时,TYPE 才成为保留字。但现有系统中有很多表和视图用作'TYPE'列名(尤其是 Oracle 数据字典)。如果 Oracle 将 TYPE 设为适当的保留字,它就会破坏所有这些系统。因此不能用作标识符的保留字列表是所有 Oracle 关键字的子集。


对总体任务的意见:

“我们从外部源(文件)获取数据,程序/脚本的工作是将这些数据推送到 Oracle 表。”

此任务分为两个部分。

首先,您应该与第三方就这些文件的标准格式达成一致。不需要发现文件的结构或内容。(或者,如果有这样的需求,因为文件是从第三方轮播中随机获取的,那么您可能不应该使用关系数据库,而应该使用其他数据库:Endeca?Python Pandas 库?)

第二个是动态创建表。如果您有商定的文件结构,那么您应该根据您的情况使用SQL*Loader外部表加载到标准表中。如果您使用 12c,也许SQL*Loader Express 模式可能会感兴趣。