2010-05-09 6 views
6

Ich möchte die Gesamtzahl der Ergebnisse und Top-N-Zeilen einer Abfrage erhalten - ist es möglich in einer Aussage?kann ich count() und Zeilen von einer SQL-Abfrage in SQL Server?

Ich würde erwarten, dass die Ergebnisse als:

count(..) column1  column2 
125   some_value some_value 
125   some_value some_value 

Vielen Dank im Voraus!

+0

ja möglich. Bitte beachten Sie den folgenden Link. http://stackoverflow.com/questions/610932/how-to-retrieve-the-total-row-count-of-a-query-with-top – Sahi

Antwort

3

Sie können tun dies mit einem CROSS JOIN und CTE, aber es ist nicht sehr effizient:

WITH Rows_CTE AS 
(
    SELECT Column1, Column2 
    FROM Table 
    WHERE (...) 
) 
SELECT c.Cnt, r.Column1, r.Column2 
FROM Rows_CTE r 
CROSS JOIN (SELECT COUNT(*) AS Cnt FROM Rows_CTE) c 

Ich glaube, einen besseren Weg zu bekommen, was würden Sie wollen eine einzelne Abfrage zu verwenden, sondern mehrere Ergebnis Sets, die Sie mithilfe von COMPUTE tun können:

SELECT Column1, Column2 
FROM Table 
WHERE (...) 
COMPUTE COUNT([Column1]) 
+0

Warum ein CTE verwenden? Ein einfaches Cross-Join auf eine abgeleitete Tabelle wird es tun. Und COMPUTE ist auch veraltet. – gbn

+0

@gbn: Ich habe ein 'CROSS JOIN' verwendet. Der CTE ist so, dass die Prädikate wiederverwendet werden können (beachten Sie die Einbeziehung von 'WHERE (...)', die in der Frage fehlt, aber wahrscheinlich in der Produktionsumgebung enthalten ist). Und ich weiß, dass "COMPUTE" technisch veraltet ist, aber "ROLLUP" kann es hier nicht ersetzen und die Verwendung von "COMPUTE" eliminiert einen kompletten Tabellen-/Index-Scan aus dem Plan. – Aaronaught

+0

Ehrlich gesagt ärgerte es mich immer, dass sie 'COMPUTE' verwarfen, weil es immer noch die einzige Möglichkeit ist, Aggregate ohne eine GROUP BY-Klausel zu berechnen. Aber das ist eine Tirade für einen anderen Tag. – Aaronaught

8

So:

SELECT TOP 100 --optional 
    MC.Cnt, M.Column1, M.Column2 
FROM 
    myTable M 
    CROSS JOIN 
    (SELECT COUNT(*) AS Cnt FROM myTable) MC 

Edit: Nach dem Downvote und COUNT/OVER Antwort. Ein Vergleich auf 2 Tische von mir

Sie können einen großen Unterschied zwischen meinem CROSS sehen JOIN/simple Aggregat und eine COUNT/leere ORDER BY-Klausel

SELECT COUNT(*) OVER() AS C, key1col, key2col 
FROM myTable 

(24717 row(s) affected) 

Table 'Worktable'. Scan count 3, logical reads 49865, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'myTable'. Scan count 1, logical reads 77, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

StmtText 
    |--Nested Loops(Inner Join) 
     |--Table Spool 
     | |--Segment 
     |   |--Index Scan(OBJECT:([MyDB].[dbo].[myTable].[IX_useful])) 
     |--Nested Loops(Inner Join, WHERE:((1))) 
      |--Compute Scalar(DEFINE:([Expr1003]=CONVERT_IMPLICIT(int,[Expr1005],0))) 
      | |--Stream Aggregate(DEFINE:([Expr1005]=Count(*))) 
      |   |--Table Spool 
      |--Table Spool 

SELECT 
    MC.Cnt, M.key1col, M.key2col 
FROM 
    myTable M 
    CROSS JOIN 
    (SELECT COUNT(*) AS Cnt FROM myTable) MC 

(24717 row(s) affected) 

Table 'myTable'. Scan count 2, logical reads 154, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 


StmtText 
    |--Nested Loops(Inner Join) 
     |--Compute Scalar(DEFINE:([Expr1005]=CONVERT_IMPLICIT(int,[Expr1009],0))) 
     | |--Stream Aggregate(DEFINE:([Expr1009]=Count(*))) 
     |   |--Index Scan(OBJECT:([MyDB].[dbo].[myTable].[IX_useful])) 
     |--Index Scan(OBJECT:([MyDB].[dbo].[myTable].[IX_useful] AS [M])) 

ich dies mit 570K Zeilen auf einem Tisch wiederholt habe und hier ist der IO

Table 'Worktable'. Scan count 3, logical reads 1535456, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'myTable'. Scan count 1, logical reads 2929, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 


Table 'myTable'. Scan count 34, logical reads 6438, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
+0

+1 für das Ziehen aller Waffen. Ich muss meine Exec-Pläne überprüfen. –

+0

@Chris Bednarski: Ich wurde schon vorher gebissen! SET STATISTICS TIME ON auch nützlich: CPU ist x5 bis x10 und Dauer x2 für die OVER-Lösung für mich – gbn

+0

@ gbn: Ich bin jetzt interessiert zu sehen, ob es zwischen 2005 und 2008 viel Unterschied in der Leistung ist. Es läuft wie ein Hund auf 2005. –

6

was

SELECT COUNT(*) OVER() AS C, COLUMN1, COLUMN2 
FROM TABLE 

Bezüglich CROSS JOIN Abfragen
In einer schweren INSERT/DELETE Umgebung gibt die Kreuzverbindung falsche Zeilenanzahl zurück.

Versuchen diese aus mehreren Verbindungen
Verbindung 1

set nocount on; 
drop table dbo.test_table; 
GO 
create table dbo.test_table 
(
    id_field uniqueidentifier not null default(newid()), 
    filler char(2000) not null default('a') 
); 
GO 
create unique clustered index idx_id_fld on dbo.test_table(id_field); 
GO 
while 1 = 1 
insert into dbo.test_table default values; 

Verbindung 2

select T2.cnt, T1.id_field, T1.filler 
from dbo.test_table T1 
cross join (select COUNT(*) as cnt from dbo.test_table) T2 

select T2.cnt, T1.id_field, T1.filler 
from dbo.test_table T1 
cross join (select COUNT(*) as cnt from dbo.test_table) T2 

select T2.cnt, T1.id_field, T1.filler 
from dbo.test_table T1 
cross join (select COUNT(*) as cnt from dbo.test_table) T2 

Jedes Mal die Anzahl der Aufzeichnungen (@@ROWCOUNT) unterschiedlich zu T2.cnt

Bei von COUNT(*) OVER(), gibt es nur einen einzigen Tabellenscan und die @@ROWCOUNT ist immer die gleiche, wie T2.cnt

In Bezug auf Abfragepläne - SQL 2005 SP3 erscheint tun COUNT(*) OVER() als SQL 2008 R2 viel schwächer. Darüber hinaus meldet es fälschlicherweise Abfragekosten (ich hätte nie gedacht, dass eine Unterabfrage mehr als 100% der gesamten Abfrage kosten könnte).

In vielen Szenarien, die Kosten für die COUNT(*) OVER() sind zwischen 50-75% der CROSS JOIN

Das beste Case-Szenario für ein Cross-Join wäre, wenn es ein sehr schmaler Index war die Zählung auf zu tun .Auf diese Weise wird ein Clustered-Index-Scan für die Daten und ein Index-Scan für die Zählung durchgeführt.

Wie immer ist es am besten zu messen, zu messen, zu messen und mit dem Kompromiss zu gehen, mit dem Sie gerne leben.

+0

Ich würde vorschlagen, das gleiche (ish) –

+0

+1 für die Verwendung der analytischen Funktion ..... –

+0

viel besser als Joins, verwendet nur einen einzigen Scan –

0

einen Versuch geben für diese Abfrage:

select ColumnId,Descr,(select COUNT(*) from ColumnSetUp)as c 
from ColumnSetUp 
group by ColumnId,Descr 
Verwandte Themen