MSDN 对 DbCommand.ExecuteScalar 方法是这样描述的:
执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。
语法: public abstract Object ExecuteScalar()
返回值: 类型: System.Object,结果集中第一行的第一列。
备注: 使用 ExecuteScalar 方法从数据库中检索单个值(例如一个聚合值)。 与使用 ExecuteReader 方法然后使用 DbDataReader 返回的数据执行生成单个值所需的操作相比,此操作需要的代码较少。如果找不到结果集中第一行的第一列;则返回 null 引用(在 Visual Basic 中为 Nothing)。 如果数据库中的该值为 null,此查询将返回 DBNull.Value。
准备测试用例
让我们这实际测试一下吧,首先准备好以下 create-table-Keywords.sql :
1 CREATE TABLE Keywords (
2 keyword_id SERIAL PRIMARY KEY,
3 keyword VARCHAR(40) NOT NULL,
4 UNIQUE KEY (keyword)
5 )
上面的 SQL 语句来源于《SQL反模式》一书 第17章 可怜人的搜索引擎 第5节 解决方案:使用正确的工具 (第159页)。
然后在 openSUSE 12.1 操作系统的 MySQL 5.5.16 数据库中执行以下 SQL 命令:
ben@vbox:~/work/SQL-Antipatterns> mysql -u test -ppwd-for-test test
mysql> source create-table-Keywords.sql;
Query OK, 0 rows affected (0.18 sec)
mysql> desc Keywords;
+------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+----------------+
| keyword_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| keyword | varchar(40) | NO | UNI | NULL | |
+------------+---------------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)
mysql> insert into Keywords (keyword) values ('crash');
Query OK, 1 row affected (0.10 sec)
在 MySQL Client 中测试
接着在 MySQL Client 中执行以下三个 SQL select 语句:
mysql> select keyword_id from Keywords where keyword = 'crash';
+------------+
| keyword_id |
+------------+
| 1 |
+------------+
1 row in set (0.01 sec)
mysql> select keyword_id from Keywords where keyword = 'aborted';
Empty set (0.00 sec)
mysql> select max(keyword_id) from Keywords where keyword = 'aborted';
+-----------------+
| max(keyword_id) |
+-----------------+
| NULL |
+-----------------+
1 row in set (0.01 sec)
mysql>
第一个 select 语句返回一个确实存在的 keyword_id 值,第二个 select 语句返回空结果集,第三个 select 语句返回的结果集中有一行数据,但是其值是 NULL,这是因为 SQL MAX() 函数在起作用。注意由于 Keywords 表的 keyword 列有 unique 索引,上面三个 select 语句返回的结果集中最多只能有一行,不可能有多行。
在 ADO.NET 中测试
我们使用以下 C# 程序 Tester.cs 来测试上述三个 SQL select 语句:
1 using System;
2 using MySql.Data.MySqlClient;
3
4 namespace Skyiv.Test
5 {
6 static class Tester
7 {
8 static void Main()
9 {
10 Test("SELECT keyword_id FROM Keywords WHERE keyword = 'crash'");
11 Test("SELECT keyword_id FROM Keywords WHERE keyword = 'aborted'");
12 Test("SELECT MAX(keyword_id) FROM Keywords WHERE keyword = 'aborted'");
13 }
14
15 static void Test(string sql)
16 {
17 using (var conn = new MySqlConnection("server=localhost;user=test;password=pwd-for-test;database=test"))
18 using (var comm = conn.CreateCommand())
19 {
20 conn.Open();
21 comm.CommandText = sql;
22 var result = comm.ExecuteScalar();
23 Console.WriteLine("Type:{0,-13} DBNull:{1,-5} null:{2,-5} Value:[{3}]",
24 (result == null) ? "(null)" : result.GetType().ToString(),
25 result is DBNull, result == null, result);
26 }
27 }
28 }
29 }
使用 Mono 2.10.6 编译和运行,结果如下所示:
ben@vbox:~/work/SQL-Antipatterns> dmcs Tester.cs -r:/home/ben/repo/dll/MySql.Data.dll && mono Tester.exe
Type:System.UInt64 DBNull:False null:False Value:[1]
Type:(null) DBNull:False null:True Value:[]
Type:System.DBNull DBNull:True null:False Value:[]
ben@vbox:~/work/SQL-Ant