我有一些创建表脚本,我需要在我的应用程序中预先验证。我可以想到两种方式:
我发现第二种方式更有效率。因此,我使用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))
我想事先得到精度溢出错误。
答案 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
通常会产生良好的效果。
EXPLAIN PLAN FOR
SET PLANONLY ON
EXPLAIN
EXPLAIN PLAN FOR
EXPLAIN
SET SHOWPLAN_ALL ON
EXPLAIN
EXPLAIN VERBOSE
另一种方法是启动事务,运行语句并回滚事务。当然,您需要进行适当的错误处理,这在服务器之间也会有所不同。在SQL Server中有TRY ... CATCH
。
还有必要检查所选DBMS中是否支持事务中的DDL语句。例如,在MySQL中“某些语句无法回滚。通常,这些语句包括数据定义语言(DDL)语句,例如创建或删除数据库的语句,创建,删除或更改表或存储的语句例程“。
答案 2 :(得分:1)
我建议(至少)你的前两个问题:
将使用Perl
的解析和数据库接口功能/特性(即Perl DBI
模块)并编写一个脚本,通过准备好的语句调用来验证SQL,而不是你的选择。 (多个)数据库。
高级代码流将是:
Perl
的{{1}}来电运行您的SQL(例如prepare()
$dbh->prepare('CREATE TABLE emp (emp_name VARCHAR2(30)')
来电准备调用准备要由数据库执行的查询。参数是任何SQL。在高端数据库上,prepare会将SQL发送到数据库服务器,数据库服务器将对其进行编译。如果prepare成功,则返回表示语句的语句句柄对象;否则它返回一个未定义的值,我们中止该程序。 $ dbh-&gt; errstr将返回失败的原因,这可能是“SQL中的语法错误”。如果可能,它会从实际数据库中获取此原因。
prepare()
还有其他一些值得一看但可能有用的模块,即:
答案 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 */