【问题标题】:How do I count the number of rows returned in my SQLite reader in C#?如何计算 C# 中我的 SQLite 阅读器中返回的行数?
【发布时间】:2009-06-07 14:59:08
【问题描述】:

我正在使用 Microsoft Visual C# 2008 Express 和 SQLite。

我正在用这样的方式查询我的数据库:

SQLiteCommand cmd = new SQLiteCommand(conn);

cmd.CommandText = "select id from myTable where word = '" + word + "';";
cmd.CommandType = CommandType.Text;
SQLiteDataReader reader = cmd.ExecuteReader();

然后我做这样的事情:

if (reader.HasRows == true) {
    while (reader.Read()) {
        // I do stuff here
    }
}

我想要做的是计算行数之前我做“reader.Read()”,因为返回的数字会影响我想要/需要做的事情。我知道我可以在 while 语句中添加一个计数,但我确实需要知道之前的计数。

有什么建议吗?

【问题讨论】:

标签: c# sqlite


【解决方案1】:

DataReader 延迟运行,因此它不会在开始之前读取整个行集。这让您有两个选择:

  1. 遍历和计数
  2. 在 SQL 语句中计数。

因为我比较喜欢 SQL,所以我会在 SQL 语句中进行计数:

cmd.CommandText = "select count(id) from myTable where word = '" + word + "';";
cmd.CommandType = CommandType.Text;
int RowCount = 0;

RowCount = Convert.ToInt32(cmd.ExecuteScalar());

cmd.CommandText = "select id from myTable where word = '" + word + "';";
SQLiteDataReader reader = cmd.ExecuteReader();

//...

注意我是如何计算 * 的,而不是一开始的 id。这是因为 count(id) 会忽略 id,而 count(*) 只会忽略完全为空的行。如果您没有空 id,则使用 count(id)(它会快一点,具体取决于您的表大小)。

更新:改成 ExecuteScalar,也基于 cmets 的 count(id)。

【讨论】:

  • 是的 - 在您的回复和 Jeremy 的回复之间,这将起作用。虽然“myTable”最终会非常大,但返回的行数可能总是很小 - 少于 10,通常它只会是 0-2。谢谢!
  • 哦——而且“id”永远不会为空。如果是,则有其他问题。 :)
  • “非常大”有多大,你确定 SQLite 是最好的吗?
  • 目前,在我一边编程一边学习的过程中,我确信 SQlite 是目前最好的。将来我是否需要更改为其他数据库解决方案?这很可能——但我还有很多其他的事情要学习和做,SQLite 目前正在满足我的需求。该表在短期内将有几千个条目,但是当我的应用程序完成并且我完全使用它时,它应该至少有 60,000 和多达 100,000
  • 这与问题没有直接关系,但我建议不要使用字符串连接来构建 sql 字符串,而是使用参数化查询来防止可能的 sql 注入。
【解决方案2】:

你的要求是不可行的——引用Igor Tandetnik,我的重点:

每次调用sqlite3_step 时,SQLite 都会根据要求一一生成记录。 它根本不知道会有多少,直到一些sqlite3_step 调用它发现没有更多了。

sqlite3_step 是 SQLite 的 C API 中的函数,C# 接口在此处为结果中的每一行调用该函数)。

您最好先做一个"SELECT COUNT(*) from myTable where word = '" + word + "';",然后再进行“真正的”查询——会告诉您将从真正的查询中获得多少行。

【讨论】:

    【解决方案3】:

    进行第二次查询:

    cmd.CommandText = "从 myTable 中选择 count(id) 其中 word = '" + word + "';"; cmd.CommandType = CommandType.Text; SQLiteDataReader 阅读器 = cmd.ExecuteReader();

    然后,您的阅读器将包含一行,其中一列包含结果集中的行数。计数将在服务器上执行,因此应该很快。

    【讨论】:

    • 注意计算单个字段:如果为null,则不计算,但会返回。在计数使用之前,请确保字段具有 NOT NULL 约束。
    • 绝对。一般来说,我希望名为“id”的字段不为空,但你永远无法确定!
    【解决方案4】:

    如果您只是从数据库中加载id 列,那么简单地加载到List<string> 然后在内存中工作不是更容易吗?

    【讨论】:

    • 如果您考虑表中有几十万行的情况,这可能不是您想要做的。最好提前运行另一个查询以查找行集的计数。
    • 这取决于“我在这里做的事情”是什么......取决于算法,大多数/所有数据都可能最终存储在内存中。
    • 另请注意,在另一条评论中,提交者指出查询通常需要 10 行,因此使用列表可能比两次往返数据库更快。
    【解决方案5】:

    通常我会这样做

    select count(1) from myTable where word = '" + word + "';";
    

    尽快得到结果。在 id 是 int 的情况下,它不会有太大的区别。如果它有点像字符串类型,那么您会注意到大型数据集的差异。

    推理 count(1) 将包括空行。但如果我错了,我准备纠正。

    【讨论】:

      【解决方案6】:

      试试这个,

      SQLiteCommand cmd = new SQLiteCommand(conn);
      
      cmd.CommandText = "select id from myTable where word = '" + word + "';";
      
      SQLiteDataReader reader = cmd.ExecuteReader();
      
      while (reader.HasRows)
      
           reader.Read();
      
      int total_rows_in_resultset = reader.StepCount;
      

      total_rows_in_resultset 为您提供处理查询后结果集中的行数

      请记住,如果您想使用同一个阅读器,请关闭此阅读器并重新启动。

      【讨论】:

        【解决方案7】:

        但我真的需要知道之前的计数

        这是为什么呢?如果您使用足够的内存数据结构(数据集、列表...),这通常不是必需的。可能有一种方法可以做您想做的事情,而无需事先计算行数。

        【讨论】:

        • 我正在尝试实现此处定义的“graphmaster”版本:alicebot.org/documentation/matching.html 基本上 - 如果有 0 或 1 行,我有一个独特的答案,不用担心。但是如果有 2 行或更多行,那么我必须做一些其他的事情来确定哪一个是正确的答案......这取决于我的“图表”中的下一个节点。这就是我能在评论中解释的最好的了! :)
        • 您可以检索列表或DataSet中的所有行,然后检查行数并根据行数对内存中的数据执行任何操作。除非查询可能会获取数百或数千行,否则这应该不是问题。
        【解决方案8】:

        你必须算上select count... from...

        这会使您的应用程序变慢。但是,有一种简单的方法可以让您的应用程序更快,那就是使用参数化查询。

        请看这里:How do I get around the "'" problem in sqlite and c#?

        (所以除了速度参数化查询还有另外两个优点。)

        【讨论】:

          【解决方案9】:
          SQLiteCommand cmd = new SQLiteCommand(conn);
          cmd.CommandText = "select id from myTable where word = '" + word + "';";
          SQLiteDataReader reader = cmd.ExecuteReader();
          
          while (reader.Read())
                 {
                    total_rows_in_resultset++;
                 }
          

          【讨论】:

          • 请添加一些解释为什么此代码有助于 OP。这将有助于为未来的观众提供一个可以学习的答案。请参阅How to Answer 了解更多信息。在回答此类老问题时,将您的答案与许多其他预先存在的答案区分开来尤为重要。
          【解决方案10】:

          当然,获得行数的更好方法是这样的:-

           SQLiteDataReader reader = SendReturnSQLCommand(dbConnection, "SELECT COUNT(*) AS rec_count FROM table WHERE field = 'some_value';");
                if (reader.HasRows) {
                   reader.Read();
                  int  count = Convert.ToInt32(reader["rec_count"].ToString());
          
          ...
          
              }
          

          这样你就不必遍历行了

          【讨论】:

          • 您能解释一下 SendReturnSQLCommand 方法的内容吗?
          【解决方案11】:

          这是我在静态方法中的完整实现。 您应该能够将其插入您的类(将 _STR_DB_FILENAME 和 STR_TABLE_NAME 替换为您的数据库文件名和表名)。

              /// <summary>
              /// Returns a count of the number of items in the database.
              /// </summary>
              /// <returns></returns>
              public static int GetNumberOfItemsInDB()
              {
                  // Initialize the count variable to be returned
                  int count = 0;            
          
                  // Start connection to db
                  using (SqliteConnection db =
                      new SqliteConnection("Filename=" + _STR_DB_FILENAME))
                  {
                      // open connection
                      db.Open();
          
                      SqliteCommand queryCommand = new SqliteCommand();
                      queryCommand.Connection = db;
          
                      // Use parameterized query to prevent SQL injection attacks
                      queryCommand.CommandText = "SELECT COUNT(*) FROM " + _STR_TABLE_NAME;
                      // Execute command and convert response to Int
                      count = Convert.ToInt32(queryCommand.ExecuteScalar());
                      // Close connection
                      db.Close();
                  }
                  // return result(count)
                  return count;
              }
          

          注意:为了提高性能,您可以在“SELECT COUNT()...”中替换 ''。使用表中主键的列名,以便在更大的数据集上获得更快的性能。

          【讨论】:

            猜你喜欢
            • 2015-07-10
            • 2021-06-04
            • 2023-03-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-08-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多