如何使用C#在执行SQL查询之前验证它?

9
我有一个文本框,用户在其中输入他的SQL查询。但是,在将其执行到数据库之前,我需要编写一个程序来验证该查询语句。
例如:
假设用户输入了:
SELECT A1,
       A2,
       A3 
  FROM XYZ

所以现在,在执行查询之前,我需要检查表XYZ中是否存在A1A2A3。如果不存在,用户应该看到一个错误消息。

我无法想出如何继续的方法。 所以,有人能给出一个基本的想法和一个样例代码片段吗?


如果你只想检查表名和列名,你可以从SQL Server的Sys表中读取所有对象并缓存它们,然后在你的应用程序中检查对象。但是,如果你想检查语法,我就不知道了。 - Mahdi Farhani
查看这个问题:https://dev59.com/OmrXa4cB1Zd3GeqPBq1J - LoekD
你可以改变方法,不检查查询,而是提供用户所有可能的列,用户可以选择。然后你就可以确保所有选定的列都存在于数据库中。 - Fabio
1
如果查询语句格式不正确或引用了不存在的对象,SQL数据库肯定会提供错误信息,因此这似乎需要付出很多努力。您认为让应用程序复制(忠实地?)这项工作有什么好处呢? - Damien_The_Unbeliever
那只是一个例子而已。用户可以输入任何查询他想要的。它必须在实际执行之前检查查询的语法是否正确以及其他所有内容。 - Ankush Soni
显示剩余2条评论
4个回答

7

我认为你不应该这样做:

  • 如果XYZ不是一个表,而是一个视图、物化视图、存储过程(取决于RDBMS),返回的是游标,那怎么办?
  • 如果XYZ是一张表,但用户没有读取它的权限(grant)怎么办?
  • 如果用户没有权限读取A2字段怎么办?

还有其他需要考虑的情况:

  • 查询可以被重写(例如在Oracle中通过FGA - Fine Grain Audit)
  • XYZ可以是任何东西的同义词,例如连接到Hadoop上的远程表的dblink,而这个Hadoop暂时停止服务

因此,我建议不要进行任何预先检查,而是执行查询,并在出现异常时解析和说明异常


你忘了提到这也是有效的SQL,但可能不是想要的:SELECT A1 FROM XYZ; DROP TABLE XYZ;。这与你的建议"在没有任何预先检查的情况下执行查询"相矛盾。 - Tim Schmelter
@Tim Schmelter:对于不期望但仍然有效的SQL,我建议使用权限(GRANT / REVOKE):如果不希望DDL(可能还有DML),那么我们就不应该授予用户执行此类操作的权限。在我的看法中,解析DROPALTER、也许是DELETEUPDATE等查询是一个糟糕的设计。 - Dmitry Bychenko

2
最合适的方法是在MS SQL中执行代码,让MS SQL找出错误。
StringBuilder  query= new StringBuilder();

query.Append("BEGIN \n");
query.Append("BEGIN TRY \n");
query.Append("    -- Table does not exist; object name resolution   \n");
query.Append("    -- error not caught.   \n");
query.Append("    --Append the variable which holds your sql query \n");
query.Append("    --For eg.: SELECT * FROM NonexistentTable;   \n");
query.Append("    END TRY \n");
query.Append("    BEGIN CATCH \n");
query.Append("      SELECT \n");
query.Append("        ERROR_NUMBER() AS ErrorNumber \n");
query.Append("       ,ERROR_MESSAGE() AS ErrorMessage; \n");
query.Append("    END CATCH \n");
query.Append("END");

使用SQLCommand的ExecuteScalar()执行查询。

SQL Server将返回提交的查询的确切错误。


1
也许您需要逐个执行操作。首先,请检查表XYZ是否存在。
SELECT * FROM INFORMATION_SCHEMA.TABLES 
           WHERE TABLE_NAME = 'XYZ';

接下来的问题是,表格中的字段名称是否存在。
SELECT * FROM   INFORMATION_SCHEMA.COLUMNS
          WHERE  TABLE_NAME = 'XYZ'
                 AND COLUMN_NAME = 'A1'
                 AND COLUMN_NAME = 'A2'
                 AND COLUMN_NAME = 'A3'

0
所以现在,在执行查询之前,我需要检查表XYZ中是否存在A1、A2和A3。
如果您想检查表中的值是否存在,则必须在表中查询。如果不执行查询,则无法找到该值是否存在于表中。
如果您正在使用SQL Server(例如),则可以使用IF EXISTS子句。
IF EXISTS(
    SELECT *
    FROM sys.columns 
    WHERE Name = 'A1' AND Name = 'A2' AND Name = 'A3' 
      AND Object_ID = Object_ID(N'XYZ'))
BEGIN

END

我认为他可以。他可以查询INFORMATION_SCHEMA以获取列名并进行检查。但是,这需要对查询进行一些重度解析才能检测到使用的列名。除非用户只有像发布的这个简单查询那样的简单查询(没有子查询和聚合函数)。 - Zein Makki
@user3185569,查询将会像已发布的那些一样。 - Ankush Soni

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接