42

我正在尝试从单个表中选择一列(无连接),并且我需要行数的计数,最好是在开始检索行之前。我已经采用了两种方法来提供我需要的信息。

方法一:

SELECT COUNT( my_table.my_col ) AS row_count
  FROM my_table
 WHERE my_table.foo = 'bar'

然后

SELECT my_table.my_col
  FROM my_table
 WHERE my_table.foo = 'bar'

方法 2

SELECT my_table.my_col, ( SELECT COUNT ( my_table.my_col )
                            FROM my_table
                           WHERE my_table.foo = 'bar' ) AS row_count
  FROM my_table
 WHERE my_table.foo = 'bar'

我这样做是因为我的 SQL 驱动程序(SQL Native Client 9.0)不允许我在 SELECT 语句上使用 SQLRowCount,但我需要知道结果中的行数,以便在分配信息之前分配一个数组。不幸的是,在我的程序的这个区域中,使用动态分配的容器不是一个选项。

我担心可能会出现以下情况:

  • SELECT for count 发生
  • 出现另一条指令,添加或删除一行
  • SELECT for data 发生,突然数组大小错误。
    - 在最坏的情况下,这将尝试写入超出数组限制的数据并使我的程序崩溃。

方法 2 是否禁止此问题?

另外,这两种方法中的一种会更快吗?如果是这样,是哪个?

最后,是否有更好的方法我应该考虑(也许是一种指示驱动程序使用 SQLRowCount 返回 SELECT 结果中的行数的方法?)

对于那些询问的人,我正在使用带有上述 SQL 驱动程序(由 Microsoft 提供)的 Native C++。

4

10 回答 10

35

如果您使用的是 SQL Server,则在查询之后您可以选择@@RowCount函数(或者如果您的结果集可能有超过 20 亿行,请使用RowCount_Big()函数)。这将返回前一个语句选择的行数或受插入/更新/删除语句影响的行数。

SELECT my_table.my_col
  FROM my_table
 WHERE my_table.foo = 'bar'

SELECT @@Rowcount

或者,如果您想在发送的结果中包含类似于方法 #2 的行数,您可以使用OVER 子句

SELECT my_table.my_col,
    count(*) OVER(PARTITION BY my_table.foo) AS 'Count'
  FROM my_table
 WHERE my_table.foo = 'bar'

与使用子查询获取行数相比,使用 OVER 子句的性能要好得多。使用 @@RowCount 将具有最佳性能,因为 select @@RowCount 语句不会有任何查询成本

更新以回应评论:我给出的示例将给出分区中的行数 - 在这种情况下由“PARTITION BY my_table.foo”定义。每行中列的值是具有相同 my_table.foo 值的行数。由于您的示例查询具有子句“WHERE my_table.foo = 'bar'”,因此结果集中的所有行都将具有相同的 my_table.foo 值,因此列中的值对于所有行都将相同且相等(在这种情况下)这是查询中的行数。

这是一个更好/更简单的示例,说明如何在每行中包含一列,即结果集中的总行数。只需删除可选的 Partition By 子句。

SELECT my_table.my_col, count(*) OVER() AS 'Count'
  FROM my_table
 WHERE my_table.foo = 'bar'
于 2008-10-28T17:23:28.923 回答
19

只有两种方法可以 100% 确定COUNT(*)实际查询会给出一致的结果:

  • 与查询相结合COUNT(*),如您的方法 2 中所示。我推荐您在示例中显示的表单,而不是 kogus 评论中显示的相关子查询表单。
  • SNAPSHOT在或SERIALIZABLE隔离级别 启动事务后,使用两个查询,如您的方法 1 。

使用其中一种隔离级别很重要,因为任何其他隔离级别都允许其他客户端创建的新行在当前事务中可见。阅读 MSDN 文档以SET TRANSACTION ISOLATION获取更多详细信息。

于 2008-10-28T17:21:49.643 回答
3

方法 2 将始终返回与您的结果集匹配的计数。

我建议您将子查询链接到您的外部查询,以确保您的计数条件与数据集上的条件匹配。

SELECT 
  mt.my_row,
 (SELECT COUNT(mt2.my_row) FROM my_table mt2 WHERE mt2.foo = mt.foo) as cnt
FROM my_table mt
WHERE mt.foo = 'bar';
于 2008-10-28T16:33:44.797 回答
3

如果您担心自执行查询和检索结果以来满足条件的行数可能会在几毫秒内发生变化,您可以/应该在事务中执行查询:

BEGIN TRAN bogus

SELECT COUNT( my_table.my_col ) AS row_count
FROM my_table
WHERE my_table.foo = 'bar'

SELECT my_table.my_col
FROM my_table
WHERE my_table.foo = 'bar'
ROLLBACK TRAN bogus

这将始终返回正确的值。

此外,如果您使用的是 SQL Server,您可以使用 @@ROWCOUNT 获取受最后一条语句影响的行数,并将实际查询的输出重定向到临时表或表变量,这样您就可以完全返回所有内容,并且无需交易:

DECLARE @dummy INT

SELECT my_table.my_col
INTO #temp_table
FROM my_table
WHERE my_table.foo = 'bar'

SET @dummy=@@ROWCOUNT
SELECT @dummy, * FROM #temp_table
于 2008-10-28T16:57:02.487 回答
1

这里有一些想法:

  • 使用方法 #1 并调整数组的大小以保存额外的结果或使用根据需要自动调整大小的类型(你没有提到你使用的是什么语言,所以我不能更具体)。
  • 如果您的数据库支持,您可以在事务中执行方法 #1 中的两个语句,以保证两次计数相同。
  • 我不确定您对数据做了什么,但如果可以在不先存储所有结果的情况下处理结果,这可能是最好的方法。
于 2008-10-28T15:50:22.513 回答
1

如果您真的担心您的行数会在 select 计数和 select 语句之间发生变化,为什么不先将您的行选择到临时表中呢?这样,您就知道您将保持同步。

于 2008-10-28T16:26:41.753 回答
0

为什么不将结果放入向量中?这样您就不必事先知道尺寸。

于 2008-10-28T15:44:19.747 回答
0

您可能想考虑一种更好的模式来处理这种类型的数据。

没有自尊的 SQL 驱动程序会在返回行之前告诉您查询将返回多少行,因为答案可能会改变(除非您使用事务,这会产生自己的问题。)

行数不会改变 - 谷歌的 ACID 和 SQL。

于 2008-10-28T16:14:09.407 回答
0
IF (@@ROWCOUNT > 0)
BEGIN
SELECT my_table.my_col
  FROM my_table
 WHERE my_table.foo = 'bar'
END
于 2010-08-02T14:26:00.293 回答
0

只是添加这个,因为这是谷歌这个问题的最高结果。在 sqlite 中,我使用它来获取行数。

WITH temptable AS
  (SELECT one,two
   FROM
     (SELECT one, two
      FROM table3
      WHERE dimension=0
      UNION ALL SELECT one, two
      FROM table2
      WHERE dimension=0
      UNION ALL SELECT one, two
      FROM table1
      WHERE dimension=0)
   ORDER BY date DESC)
SELECT *
FROM temptable
LEFT JOIN
  (SELECT count(*)/7 AS cnt,
                        0 AS bonus
   FROM temptable) counter
WHERE 0 = counter.bonus
于 2015-05-09T11:47:10.500 回答