【问题标题】:Validate syntax of CREATE TABLE DDLs using EXPLAIN Command使用 EXPLAIN 命令验证 CREATE TABLE DDL 的语法
【发布时间】:2016-12-04 00:41:13
【问题描述】:

我有一些创建表脚本需要在我的应用程序中进行预验证。我可以想到两种方法:

  1. 使用该脚本创建表并立即删除表。
  2. 使用 EXPLAIN 命令查找语法错误而不创建它。

我发现第二种方式更有效。因此,我使用 Explain 命令验证了 CREATE TABLE DDL。

工作:

Teradata

Explain <CREATE TABLE DDL>

甲骨文

EXPLAIN PLAN FOR <CREATE TABLE DDL>

不工作:

SQL 服务器

找不到存储过程“解释”。 SQL 状态:S00062 错误代码:2812

Netezza

^ 发现“CREATE”(字符 18)期待 DELETE' orINSERT' 或 SELECT' orUPDATE' 或 `WITH'

DB2

错误:DB2 SQL 错误:SQLCODE=-104, SQLSTATE=42601, SQLERRMC=TABLE;EXPLAIN CREATE ;JOIN, DRIVER=4.14.111 SQL 状态:42601 错误代码:-104


  • 还有其他更好的方法来验证 Create Table DDL 吗?

  • 是否有任何通用方法可以在流行的 RDBMS 中处理此问题?

  • 如果解释是唯一可用的解决方案,如何为 SQL Server、Netezza 和 DB2 执行解释?

编辑:

这里的 validate 表示检查语法(存储大小、精度、比例范围违规、保留关键字作为表或列名等

例如查询-

create table abc (c1 decimal(555,44))

我想事先得到精度溢出错误。

【问题讨论】:

  • “验证”到底是什么意思?
  • @NicholasKrasnov validate 表示查找精度、比例溢出等。例如create table abc (c1 decimal(555,44))
  • 在 Oracle 中,没有本地方法可以解析 DDL 语句来检查它在语法和/或语义上是否正确,而无需实际执行它。 explain plan (尽管它不是它的目的)尽可能接近解析 DDL 语句而不实际执行它。 DML 解析(不执行语句)可以用 dbms_sql.parse() 完成 - 将执行 DDL 语句。
  • "是否有任何通用的方法可以在流行的 RDBMS 中处理这个问题?" - 不,绝对没有。
  • @a_horse_with_no_name 好的,谢谢...!

标签: sql-server oracle db2 teradata netezza


【解决方案1】:

没有适用于所有 DBMS 的通用/标准方法。

我希望所有流行的 DBMS 都有类似于 EXPLAIN 命令的东西。返回执行计划而不是运行查询本身的东西。每个服务器都有自己的处理方式。

http://use-the-index-luke.com/sql/explain-plan 展示了如何为少数 DBMS 执行此操作。搜索&lt;your DBMS name&gt; explain plan command 通常会得到很好的结果。


另一种方法是启动事务,运行语句并回滚事务。当然,您需要进行适当的错误处理,这在服务器之间又有所不同。在 SQL Server 中有TRY ... CATCH

还值得检查所选 DBMS 是否支持事务中的 DDL 语句。例如,在MySQL“某些语句不能回滚。通常,这些语句包括数据定义语言 (DDL) 语句,例如创建或删除数据库的语句,创建、删除或更改表或存储例程的语句。 "

【讨论】:

    【解决方案2】:

    您应该能够使用仅格式选项SET FMTONLY ON 在 SQL Server 中评估查询的正确性。使用此选项集,SQL Server 将不会实际尝试创建表。使用您的示例,T-SQL 将如下所示:

    SET FMTONLY ON
    create table abc (c1 decimal(555,44))
    SET FMTONLY OFF
    

    执行上述T-SQL会返回错误信息'Column or parameter #1: Specified column precision 555 is greater than the maximum precision of 38.'

    您还可以创建一个存储过程,使用在您使用的数据库平台上效果最好的方法为您评估查询。我不熟悉 Netezza、Teradata 和 DB2,但我假设它们可以执行动态 SQL。使用此方法,您只需将要评估的查询作为参数从应用程序层传递给存储过程。 以下代码 sn-p 显示了如何为 SQL Server 完成此操作:

    CREATE PROCEDURE ValidateQuerySyntax
    (
        @query NVARCHAR(MAX)
    )
    AS
    BEGIN
    
        SET NOCOUNT ON;
    
        DECLARE @validationQuery NVARCHAR(MAX) = 'SET FMTONLY ON; ' + CHAR(13) + @query + ';' +  CHAR(13) + 'SET FMTONLY OFF;';
    
        BEGIN TRY
            EXEC (@validationQuery);
    
            -- Return error code 0 if query validation was successful.
            SELECT  
                 0 AS ErrorNumber  
                ,0 AS ErrorSeverity  
                ,0 AS ErrorState  
                ,0 AS ErrorLine  
                ,'Query evaluated successfully' AS ErrorMessage; 
    
        END TRY  
        BEGIN CATCH  
    
            -- Return error information if query validation failed.
            SELECT  
                 ERROR_NUMBER() AS ErrorNumber  
                ,ERROR_SEVERITY() AS ErrorSeverity  
                ,ERROR_STATE() AS ErrorState  
                ,ERROR_LINE() AS ErrorLine  
                ,ERROR_MESSAGE() AS ErrorMessage; 
        END CATCH; 
    
    END
    

    查询可以按如下方式评估:

    DECLARE @query_1 NVARCHAR(MAX) = 
    'CREATE TABLE A 
    (   
         c1 INT
    )';
    
    DECLARE @query_2 NVARCHAR(MAX) = 
    'CREATE TABLE B 
    (   
         c1 INT
         c2 INT
    )';
    
    DECLARE @query_3 NVARCHAR(MAX) = 
    'CREATE TABLE B 
    (   
         c1 INT
         ,c2 DECIMAL(555,44)
    )';
    
    EXEC dbo.ValidateQuerySyntax @query = @query_1;
    
    EXEC dbo.ValidateQuerySyntax @query = @query_2;
    
    EXEC dbo.ValidateQuerySyntax @query = @query_3;
    

    上述验证调用的输出如下:

    -------------------------------------------------------------------------------------------------------------------------------------------------------------
    ErrorNumber | ErrorSeverity | ErrorState    | ErrorLine | ErrorMessage
    -------------------------------------------------------------------------------------------------------------------------------------------------------------
    0           | 0             | 0             | 0         | Query evaluated successfully
    -------------------------------------------------------------------------------------------------------------------------------------------------------------
    102         | 15            | 1             | 4         | Incorrect syntax near 'c2'.
    -------------------------------------------------------------------------------------------------------------------------------------------------------------
    2750        | 16            | 1             | 1         | Column or parameter #2: Specified column precision 555 is greater than the maximum precision of 38.
    -------------------------------------------------------------------------------------------------------------------------------------------------------------
    

    当然,这确实意味着创建存储过程来首先为您评估查询,但它应该简化跨不同数据库平台的查询验证。

    【讨论】:

      【解决方案3】:

      我对(至少)您的前两个问题的建议:

      • 还有其他更好的方法来验证 Create Table DDL 吗?
      • 是否有任何通用方法可以在流行的 RDBMS 中处理此问题?

      将使用Perl 的解析和数据库接口功能/特性(即Perl DBI 模块)并编写一个脚本,通过针对您选择的数据库的准备好的语句调用来验证SQL .

      高级代码流是:

      1. 连接到您选择的数据库
      2. 通过Perlprepare() 调用运行您的SQL(例如$dbh-&gt;prepare('CREATE TABLE emp (emp_name VARCHAR2(30)')
      3. 检查prepare()调用的输出状态

      来自A Short Guide to DBI

      prepare 调用准备由数据库执行的查询。参数是任何 SQL。在高端数据库上,prepare 会将 SQL 发送到数据库服务器,数据库服务器将对其进行编译。如果prepare成功,则返回代表该语句的语句句柄对象;否则它返回一个未定义的值,我们中止程序。 $dbh->errstr 将返回失败的原因,可能是“SQL 中的语法错误”。如果可能,它会从实际数据库中获取这个原因。

      Perl 有一些其他的模块值得一看并且可能有用,即:

      SQL::Translator

      SQL::Statement

      【讨论】:

        【解决方案4】:

        可能是针对 DDL 语句的字符串发出的 SQL PREPARE 语句;当 DDL CREATE TABLE 语句无效时,应该显示 SQLCODE 和 SQLSTATE。类似于以下类似 REXX 的伪代码:

        sCrtTable="create table abc (c1 decimal(555,44))" ;
        prepare DDL_stmt from :sCrtTable ;
        say sqlCode ":" sqlState ; /* e.g.: "-604 : 42611"  per invalid length attribute */ 
        

        【讨论】:

          猜你喜欢
          • 2018-06-06
          • 1970-01-01
          • 1970-01-01
          • 2018-03-16
          • 2013-09-26
          • 1970-01-01
          • 1970-01-01
          • 2021-05-15
          • 2020-05-27
          相关资源
          最近更新 更多