在SELECT语句之后需要行计数:什么是最佳SQL方法?
我试图从单个表中选择一个列(没有连接),我需要计数行数,理想情况下,我开始检索行之前。我提出了两种方法来提供我需要的信息。在SELECT语句之后需要行计数:什么是最佳SQL方法?
方法1:
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本机客户端9.0)不允许我在SELECT语句中使用SQLRowCount,但我需要知道结果中的行数,才能在将信息分配给它之前分配数组。不幸的是,在我的程序的这个区域中不能使用动态分配的容器。
我关注的是以下情形可能会发生:
- SELECT COUNT位发生
- 会出现另一种指令,增加或出现数据和突然数组是错误的移除一行
- SELECT尺寸。
- 在最坏的情况下,这将尝试写入超出数组极限的数据并使我的程序崩溃。
方法2是否禁止此问题?
此外,两种方法之一会更快吗?如果是这样,哪个?
最后,有没有更好的方法,我应该考虑(也许是一种方式来指示司机用SQLROWCOUNT返回的行数在SELECT结果?)
对于那些问,我用母语C++与上述SQL驱动程序(由Microsoft提供)。
只有两种方法可以100%肯定的是,COUNT(*)
和实际查询将给予一致的结果:
- 结合
COUNT(*)
与您的方法2中的查询相同。我推荐您在示例中显示的表单,而不是从注释中显示的相关子查询表单。 - 在启动
SNAPSHOT
或SERIALIZABLE
隔离级别的事务后,使用两个查询,如在您的方法1中。
使用其中一个隔离级别很重要,因为任何其他隔离级别都允许其他客户端创建的新行在当前事务中可见。有关更多详细信息,请阅读有关SET TRANSACTION ISOLATION
的MSDN文档。
这里有一些想法:
- 围棋与方法#1和调整数组来保存额外的结果或使用类型自动调整为neccessary(你不提您所使用的语言,所以我不能更具体)。
- 您可以在事务内的方法#1中执行这两个语句,以确保如果您的数据库支持这一点,计数都是相同的。
- 我不确定你对数据做了什么,但如果可以处理结果而不先存储所有的结果,这可能是最好的方法。
您可能想要考虑处理此类数据的更好模式。
无自prespecting SQL司机会告诉你有多少行的查询将返回行之前返回,因为答案可能会改变(除非你使用一个交易,它创建了自己的问题。)
的行数不会改变 - 谷歌的ACID和SQL。
如果您真的担心您的行计数会在select count和select语句之间发生变化,为什么不先选择您的行到临时表中?这样,你知道你会同步。
方法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';
如果你关注的是,由于符合结果的查询和检索的执行情况可能会在几毫秒内改变行,你可以/应该执行一个事务中的查询数:
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获取最后一条语句影响的行数,并将输出real查询重定向到临时表或表变量,这样您可以返回的一切完全,没必要一个交易:
DECLARE @dummy INT
SELECT my_table.my_col
INTO #temp_table
FROM my_table
WHERE my_table.foo = 'bar'
SET @[email protected]@ROWCOUNT
SELECT @dummy, * FROM #temp_table
如果您使用的是SQL Server,查询后您可以选择@@ RowCount函数(或者如果结果集可能有超过20亿行,则使用BIGROW_COUNT()函数)。这将返回前一个语句选择的行数或插入/更新/删除语句影响的行数。
SELECT my_table.my_col
FROM my_table
WHERE my_table.foo = 'bar'
SELECT @@Rowcount
或者,如果你想要的行计数结果中包括发送类似的方法2,您可以使用OVER子句(见http://msdn.microsoft.com/en-us/library/ms189461.aspx1)。
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'
IF (@@ROWCOUNT > 0)
BEGIN
SELECT my_table.my_col
FROM my_table
WHERE my_table.foo = 'bar'
END
我想补充这一点,因为这是顶级的结果在谷歌的这个问题。 在sqlite中,我使用它来获取rowcount。
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
你对这些数据做了什么,你需要原始数据和行数?如果你需要所有的原始数据(这是你正在选择的),你不能在读它的时候把它计算在内吗?如果你不需要所有的原始数据,那么不要选择它。计数仅用于分页目的吗? – 2009-01-06 06:34:55