从用户获取SQL查询并在SQL Server上运行
本文关键字:SQL Server 运行 查询 用户 获取 | 更新日期: 2023-09-27 18:05:55
我想用c#开发一个非常小的应用程序,从用户那里获得一些SQL查询,并在指定的SQL Server上执行。
SQL Server和数据库必须由用户指定,因此任何事情都可以更改。我的问题是用户可以输入各种类型的SQL查询,并且每个查询都应该以自己的方式运行。例如
SELECT * FROM mytable
和
UPDATE mytable
SET city = "NY"
WHERE name = "tom"
不能以同样的方式执行。
我认为我需要在我的代码中识别用户查询类型,是否有任何方法来识别它或任何更好的方式来运行任何可能的查询?
我会使用TSqlPerser.ParseStatementList
方法从Microsoft.SqlServer.TransactSql.ScriptDom
命名空间(参考|下载#1 - Nuget下载#2 - Microsoft®SQL Server®2014 Transact-SQL ScriptDom):
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SqlServer.TransactSql.ScriptDom;
using System.IO;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
TextReader rdr = new StreamReader(new MemoryStream(
Encoding.UTF8.GetBytes(
@"/* comment */
WITH CteUpdate
AS
(
SELECT * FROM Table1
WHERE Col1 = 1
)
UPDATE CteUpdate SET city = ""NY"" WHERE name = ""tom""")
));
TSql110Parser parser = new TSql110Parser(true);
IList<ParseError> errors;
StatementList stmtList = parser.ParseStatementList(rdr, out errors);
// Process errors
foreach(TSqlStatement stmt in stmtList.Statements)
{
Console.WriteLine("Statement type {0}", stmt.GetType());
if (stmt is SelectStatement)
{
//Process SELECT statment
}
else if (stmt is UpdateStatement)
{
//Process UPDATE statment
UpdateStatement stmtUpdate = (UpdateStatement)stmt;
NamedTableReference tabRef = (NamedTableReference)stmtUpdate.UpdateSpecification.Target;
Console.Write(" > UPDATE statement > target object {0}", tabRef.SchemaObject.BaseIdentifier.Value);
}
else //Process other statments
{
throw new NotImplementedException();
}
}
}
}
}
输出:语句类型Microsoft.SqlServer.TransactSql.ScriptDom.UpdateStatement> UPDATE语句>目标对象
(此答案假设您使用System.Data.SqlClient
名称空间中可用的类)
最简单,但不是万无一失的方法是检查第一个单词-如果它(不区分大小写)等于SELECT
,您可以使用ExecuteReader()
-如果不是,您可以使用ExecuteNonQuery()
。
另一个选择是直接到ExecuteNonQuery()
。如果将SELECT语句作为CommandText
传递,则返回-1。检测到这一点后,可以调用ExecuteReader()
。但是,其他查询如BEGIN TRANSACTION
也将返回-1。
您不需要在代码中创建不同的查询类型。SqlCommand ExecuteReader方法可用于所有DML
和DDL
语句。如果语句没有返回任何结果,SqlDataReader Read方法将返回false。您还需要调用SqlDataReader。NextResult方法,直到返回false,返回多个语句的结果。
var reader = command.ExecuteReader();
do{
while(reader.Read())
{
//process resultset here
}
}while(reader.NextResult());
我会简单地给用户两个执行按钮,一个用于非查询,一个用于读取。
如果你相信用户会写sql语句,你就可以相信用户知道该点击哪个按钮。
不尝试自己分析sql语句的原因很简单:可以写一些像exec stp_doesThisProcedureSelectsOrUpdates
这样的东西,所以你根本无法告诉…