使用EXPLAIN命令验证CREATE TABLE DDL的语法

时间:2016-07-29 10:21:35

标签: sql-server oracle db2 teradata netezza

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

  1. 使用该脚本创建表并立即使用DROP表。
  2. 使用EXPLAIN命令查找语法错误而不创建它。
  3. 我发现第二种方式更有效率。因此,我使用Explain命令验证了CREATE TABLE DDL。

    工作:

    Teradata的

    Explain <CREATE TABLE DDL>
    

    的Oracle

    EXPLAIN PLAN FOR <CREATE TABLE DDL>
    

    不工作:

    SQL SERVER

      

    无法找到存储过程&#39;解释&#39;。   SQLState:S00062   ErrorCode:2812

    Netezza公司

      

    ^找到&#34;创建&#34; (在char 18)期待DELETE' or INSERT&#39;或SELECT' or更新&#39;或者“WITH&#39;

    DB2

      

    错误:DB2 SQL错误:SQLCODE = -104,SQLSTATE = 42601,SQLERRMC = TABLE; EXPLAIN CREATE; JOIN,DRIVER = 4.14.111   SQLState:42601   ErrorCode:-104

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

    • 有没有通用的方法来处理流行的RDBMS?

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

    编辑:

    此处验证意味着检查语法(存储大小,精度,范围违规,保留关键字作为表或列名称等

    例如,查询如 -

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

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

4 个答案:

答案 0 :(得分:1)

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

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

执行上述T-SQL将返回错误消息'列或参数#1:指定列精度555大于最大精度38。'

您还可以创建一个存储过程,使用在您正在使用的数据库平台上运行最佳的方法为您评估查询。我不熟悉Netezza,Teradata&amp; DB2,但我假设他们可以执行动态SQL。使用此方法,您只需将要评估的查询作为参数传递给应用程序层中的存储过程。 以下代码段显示了如何为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.
-------------------------------------------------------------------------------------------------------------------------------------------------------------

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

答案 1 :(得分:1)

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

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

http://use-the-index-luke.com/sql/explain-plan显示了如何为少数DBMS执行此操作。搜索<your DBMS name> explain plan command通常会产生良好的效果。

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

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

答案 2 :(得分:1)

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

  • 还有其他更好的方法来验证Create Table DDL吗?
  • 有没有通用的方法来处理流行的RDBMS?

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

高级代码流将是:

  1. 连接到您选择的数据库
  2. 通过Perl的{​​{1}}来电运行您的SQL(例如prepare()
  3. 检查$dbh->prepare('CREATE TABLE emp (emp_name VARCHAR2(30)')来电
  4. 的输出状态

    来自A Short Guide to DBI

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

    prepare()还有其他一些值得一看但可能有用的模块,即:

    SQL::Translator

    SQL::Statement

答案 3 :(得分:0)

可能是针对作为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 */