2008-10-28 45 views
30

我試圖從單個表中選擇一個列(沒有連接),我需要計數行數,理想情況下,我開始檢索行之前。我提出了兩種方法來提供我需要的信息。在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提供)。

+0

你對這些數據做了什麼,你需要原始數據和行數?如果你需要所有的原始數據(這是你正在選擇的),你不能在讀它的時候把它計算在內嗎?如果你不需要所有的原始數據,那麼不要選擇它。計數僅用於分頁目的嗎? – 2009-01-06 06:34:55

回答

15

只有兩種方法可以100%肯定的是,COUNT(*)和實際查詢將給予一致的結果:

  • 結合COUNT(*)與您的方法2中的查詢相同。我推薦您在示例中顯示的表單,而不是從註釋中顯示的相關子查詢表單。
  • 在啓動SNAPSHOTSERIALIZABLE隔離級別的事務後,使用兩個查詢,如在您的方法1中。

使用其中一個隔離級別很重要,因爲任何其他隔離級別都允許其他客戶端創建的新行在當前事務中可見。有關更多詳細信息,請閱讀有關SET TRANSACTION ISOLATION的MSDN文檔。

-1

爲什麼不把你的結果放到一個向量中?這樣你就不必事先知道尺寸。

+0

我應該提到你的解決方案發生在我身上,但我不喜歡將我的信息從數據庫複製到矢量,獲取行數,然後將矢量中的所有內容複製到數組中的想法。 在這種情況下,我無法更改簡單數組的使用。 – antik 2008-10-28 15:54:04

+0

數據庫查詢的結果集可能很大 - 它甚至可能不適合內存 - 所以在知道結果集是否適合之前強制結果集進入內存是不可取的。 – 2008-10-28 15:55:00

+0

如果結果集太大,你應該可以分頁。 – jonnii 2008-10-28 16:05:11

1

這裏有一些想法:

  • 圍棋與方法#1和調整數組來保存額外的結果或使用類型自動調整爲neccessary(你不提您所使用的語言,所以我不能更具體)。
  • 您可以在事務內的方法#1中執行這兩個語句,以確保如果您的數據庫支持這一點,計數都是相同的。
  • 我不確定你對數據做了什麼,但如果可以處理結果而不先存儲所有的結果,這可能是最好的方法。
0

您可能想要考慮處理此類數據的更好模式。

無自prespecting SQL司機會告訴你有多少行的查詢將返回行之前返回,因爲答案可能會改變(除非你使用一個交易,它創建了自己的問題。)

的行數不會改變 - 谷歌的ACID和SQL。

1

如果您真的擔心您的行計數會在select count和select語句之間發生變化,爲什麼不先選擇您的行到臨時表中?這樣,你知道你會同步。

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'; 
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獲取最後一條語句影響的行數,並將輸出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 
25

如果您使用的是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' 
0
IF (@@ROWCOUNT > 0) 
BEGIN 
SELECT my_table.my_col 
    FROM my_table 
WHERE my_table.foo = 'bar' 
END 
0

我想補充這一點,因爲這是頂級的結果在谷歌的這個問題。 在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 
相關問題