如何直接执行SQL语句

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何直接执行SQL语句相关的知识,希望对你有一定的参考价值。

  1、ExecuteQuery方法

  看命名,我们很容易联想到ADO.NET里熟悉的Command的ExecuteNonQuery方法,但是VS的智能提示告诉我们这个方法返回的是一个泛型集合,应该“所思非所得”。下面通过一个简单方法,验证我们的猜想(数据库设计可以参考这一篇):

  /// <summary>
  /// 直接执行sql语句,获取总人数
  /// </summary>
  /// <returns></returns>
  publicint GetTotalCount()
  
  string strSql = "SELECT COUNT(0) FROM Person(NOLOCK)";
   var query = dataContext.ExecuteQuery<int>(strSql);
  int result = query.First<int>();
  Console.WriteLine();
  Console.WriteLine("total count:0", result);
  return result;
  

  调试的时候,通过IntelliTrace跟踪到:

  毫无疑问,上面的图片说明最初的想法是不正确的,”ADO.NET:执行Reader…”云云,让我们更加坚信它实际执行的应该是ExecuteReader方法。当然最简单的方法是直接查看它的方法说明:

  // 摘要:
  // 直接对数据库执行 SQL 查询并返回对象。
  //
  // 参数:
  // query:
  // 要执行的 SQL 查询。
  //
  // parameters:
  // 要传递给命令的参数数组。注意下面的行为:如果数组中的对象的数目小于命令字符串中已标识的最大数,
  则会引发异常。如果数组包含未在命令字符串中引用的对象,则不会引发异常。如果某参数为
  // null,则该参数会转换为 DBNull.Value。
  //
  // 类型参数:
  // TResult:
  // 返回的集合中的元素的类型。
  //
  // 返回结果:
  // 由查询返回的对象的集合。
  public IEnumerable<TResult> ExecuteQuery<TResult>(string query, paramsobject[] parameters);

  ExecuteQuery方法还有一个非泛型方法:

  //
  // 摘要:
  // 直接对数据库执行 SQL 查询。
  //
  // 参数:
  // elementType:
  //

  要返回的 System.Collections.Generic.IEnumerable<T>
的类型。使查询结果中的列与对象中的字段或属性相匹配的算法如下所示:如果字段或属性映射到特定列名称,则结果集中应包含该列名称。如果未映射字段或属性,则结果集中应包含其名称与该字段或属性相同的列。通过先查找区分大小写的匹配来执行比较。如果未找到匹配项,则会继续搜索不区分大小写的匹配项。如果同时满足下列所有条件,则该查询应当返回(除延迟加载的对象外的)对象的所有跟踪的字段和属性:T

  // 是由 System.Data.Linq.DataContext 显式跟踪的实体。
  System.Data.Linq.DataContext.ObjectTrackingEnabled
  // 为 true。实体具有主键。否则会引发异常。
  //
  // query:
  // 要执行的 SQL 查询。
  //
  // parameters:
  // 要传递给命令的参数数组。注意下面的行为:如果数组中的对象的数目小于命令字符串中已标识的最大数,
  则会引发异常。如果数组包含未在命令字符串中引用的对象,则不会引发异常。如果某参数为
  // null,则该参数会转换为 DBNull.Value。
  //
  // 返回结果:
  // 由查询返回的对象的 System.Collections.Generic.IEnumerable<T> 集合。
  public IEnumerable ExecuteQuery(Type elementType, string query, paramsobject[] parameters);

  看它的参数需要多传递一个elementType,明显不如泛型方法简洁。

  2、ExecuteCommand方法

  同样道理,这个方法立刻让我们联想到(世界没有联想,生活将会怎样?),联想到,等等,不知联想到什么。然后我们看一下方法使用说明:

  //
  // 摘要:
  // 直接对数据库执行 SQL 命令。
  //
  // 参数:
  // command:
  // 要执行的 SQL 命令。
  //
  // parameters:
  // 要传递给命令的参数数组。注意下面的行为:如果数组中的对象的数目小于命令字符串中已标识的最大数,
  则会引发异常。如果数组包含未在命令字符串中引用的对象,则不会引发异常。如果任一参数为
  // null,则该参数会转换为 DBNull.Value。
  //
  // 返回结果:
  // 一个 int,表示所执行命令修改的行数。
  publicint ExecuteCommand(string command, paramsobject[] parameters);

  到这里,看它的返回类型为int,表示执行命令修改的行数,这次很容易想到ExecuteNonQuery方法。对不对呢?通过下面的代码证明我们的设想:

  /// <summary>
  /// 直接执行sql语句 根据用户Id更新体重
  /// </summary>
  /// <param name="id">用户Id</param>
  /// <param name="destWeight">更新后的体重</param>
  /// <returns></returns>
  publicint ModifyWeightById(int id, double destWeight)
  
  string strSql = string.Format("UPDATE Person SET Weight=0 WHERE Id=1", destWeight, id);
  int result = dataContext.ExecuteCommand(strSql);
   Console.WriteLine();
  Console.WriteLine("affect num:0", result);
  return result;
  

  调试过程中,通过IntelliTrace可以很清楚地捕获:

  

  “ADO.NET:执行NonQuery…”基本可以断言我们的设想是正确的。

  3、防止sql注入

  1和2中,执行sql语句的两个方法都有一个params 类型的参数,我们又会想到ADO.NET非常重要的sql语句的参数化防止sql注入问题。下面通过一个方法,看看linq2sql可不可以防止sql注入。

  (1)、直接执行拼接的sql语句(有风险)

  /// <summary>
  /// 直接执行sql语句 根据用户Id更新FirstName
  /// </summary>
  /// <param name="id">用户Id</param>
  /// <param name="destName">更新后的FirstName</param>
  /// <returns></returns>
  publicint ModifyNameById(int id, string destName)
  
  string strSql = string.Format("UPDATE Person SET FirstName=\'0\' WHERE Id=1", destName, id);
  //这么拼接有风险
  int result = dataContext.ExecuteCommand(strSql);
  Console.WriteLine();
  Console.WriteLine("affect num:0", result);
  return result;
  

  然后,在客户端这样调用这个方法:

  int result = ServiceFactory.CreatePersonService().ModifyNameById(10, "\'Anders\'");
  //更新id为10的人的FirstName
参考技术A SQL 语句摘要可以用在mysql的各个方面,比如 性能字典里对语句的分析,查询重写插件规则改写等等。
接下来依次看下语句摘要在这两方面的使用。
1. 性能字典
mysql> call sys.ps_setup_enable_consumer('statements');
+---------------------+
| summary |
+---------------------+
| Enabled 4 consumers |
+---------------------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
开启后,执行几次之前的几条 SQL。
完后可以很方便的从 sys 库里分析这类语句的执行情况,包括执行次数,执行时间,扫描的记录数,锁定的时间,是否用到排序等等。

2. 查询重写插件
比如要阻止对表 p1 通过字段 r1 的删除动作,可以用查询重写插件在 MySQL 语句分析层直接转换,这时候就得用到摘要函数 statement_digest_text。
假设:表 p1 字段 id 值全部为正。
delete from p1 where id = 1000;

要改写为,
delete from p1 where id = -1;

利用函数 statement_digest_text 来定制这条 SQL 的重写规则。
mysql> INSERT INTO query_rewrite.rewrite_rules (pattern, replacement,pattern_database) -> VALUES( -> statement_digest_text('delete from p1 where id = 1000') , -> statement_digest_text('delete from p1 where id = -1'), -> 'ytt' -> );Query OK, 1 row affected (0.01 sec)
语句被查询重写后的效果:
mysql> delete from p1 where id = 20000;Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show warnings\G*************************** 1. row *************************** Level: Note Code: 1105Message: Query 'delete from p1 where id = 20000' rewritten to 'DELETE FROM `p1` WHERE `id` = - 20000' by a query rewrite plugin1 row in set (0.00 sec)mysql> select count(*) from p1;+----------+| count(*) |+----------+| 9000001 |+----------+1 row in set (1.59 sec)
总结
MySQL 8.0 新增的语句摘要函数可以很方便的分析 SQL 语句执行的各个方面,比以前分析类似的场景要简单的多。

如何在plsql 执行导入导入语句: 在dos下能直接执行exp 和imp语句,但plsql下执行报错?

参考技术A 首先你要知道pl\sql 是一个数据库开发工具,在pl\sql 里操作是对用户可见的,其后台执行 exp 和 imp 命令,操作过程用图形界面显示了。而cmd里运行是调用了系统里的exp.exe和imp.exe程序执行的,是前端显示操作。
你在pl\sql 里操作导出导入,因为后台已经有命令操作,所以你再按部就班写命令,重复了肯定错啊。
参考技术B exec rc(''exp userid=yuechaotian/test@s9i tables=(test_tianyc) file=c:\mygirl.dmp'');本回答被提问者采纳

以上是关于如何直接执行SQL语句的主要内容,如果未能解决你的问题,请参考以下文章

ThinkPHP里怎么直接执行一句SQL语句

python之django直接执行sql语句

SQL 查看SQL语句的执行时间 直接有效的方法

Python Django 之 直接执行自定义SQL语句

Oracle数据库的sqlplus可以直接执行SQL语句吗?

PHP中如何判断SQL语句是不是成功执行?