2010-01-26 14 views
24

Ich habe einen sehr fetten allgemeinen Tabellenausdruck, der Zeilennummern enthält, so dass ich eine seitenweise Ergebnismenge zurückgeben kann. Ich möchte auch die Gesamtzahl der Datensätze zurückgeben, die der Abfrage entsprechen, bevor ich die Ergebnismenge page.Wie wird ein CTE zweimal referenziert?

Offensichtlich ist meine obige Abfrage lückenhaft, aber es ist nur zur Veranschaulichung meines Punktes. Ich möchte eine Seite mit Ergebnissen UND die Gesamtzahl der Übereinstimmungen. Wie kann ich das tun, ohne das gesamte CTE mit mehr als 20 Zeilen kopieren und einfügen zu müssen?

+3

Ich würde vielleicht in Erwägung ziehen, diese Frage umzubenennen, da die angenommene Antwort den CTE nicht zweimal verwendet. –

Antwort

15

Sie können Kommas verwenden, um mehrere CTEs zu erstellen, die auf die oben aufgeführten CTEs verweisen.

Nur um zu zeigen, was ich meine:

with recs as (
select 
    *, 
    row_number() over (order by id) as rownum from ...... 
    ), 
counts as (
    select count(*) as totalrows from recs 
) 
select recs.*,count.totalrows 
from recs 
cross apply counts 
where rownum between @a and @b .... 

Dies ist nicht das eine gute Lösung ist.

Die beste Lösung, die ich gefunden habe, um die Gesamtzahl in einem CTE zu haben, ohne die Datensätze zu zählen, ist in this article beschrieben.

DECLARE @startRow INT; SET @startrow = 50; 
WITH cols 
AS 
(
    SELECT table_name, column_name, 
     ROW_NUMBER() OVER(ORDER BY table_name, column_name) AS seq, 
     ROW_NUMBER() OVER(ORDER BY table_name DESC, column_name desc) AS totrows 
    FROM [INFORMATION_SCHEMA].columns 
) 
SELECT table_name, column_name, totrows + seq -1 as TotRows 
FROM cols 
WHERE seq BETWEEN @startRow AND @startRow + 49 
ORDERBY seq 
+0

Ja, ich dachte darüber nach, aber es gibt ein Problem, wenn die Abfrage keine Datensätze zurückgibt. Ich schätze, ich könnte es mit einer UNION ALL und einer Dummy-Reihe täuschen ... –

+0

Schau dir das letzte Stück Code an, das ich aus dem Artikel genommen habe. Was ist, hat es eine aufsteigende und absteigende Anzahl von Zeilen und fügt sie einfach in die Ergebnisse ein, um die Gesamtzahl der Zeilen zu erhalten. Dies ist in unseren Produktionsumgebungen sehr gut. –

+1

Ahh brilliant! Diese Verbindung hat einen wirklich guten Weg, dies zu erreichen. –

19

Glauben Sie nicht, dass Sie können. Von MSDN

Ein gemeinsamen Tabellenausdruck (CTE) gedacht als eine temporäre Ergebnismenge sein kann, die innerhalb der Ausführungs Rahmen eines einzigen SELECT, INSERT definiert ist, UPDATE, DELETE oder CREATE VIEW Erklärung.

Schwerpunkt auf "einzelne SELECT, INSERT, UPDATE, DELETE oder CREATE VIEW-Anweisung."

Dies könnte eine Situation sein, in der Sie eine Temporary Table verwenden möchten.

CREATE TABLE #Recs 
{ 
    ..... 
} 
INSERT INTO #Recs 
select *, row_number() over (order by id) as rownum from ...... 

Wenn Sie nicht wissen, die Struktur der Tabelle, bevor die Hand Sie dieses Formular verwenden, um eine temporäre Tabelle zu erstellen:

select *, row_number() over (order by id) as rownum INTO #Recs from ...... 

Sie die temporäre Tabelle in der Art und Weise nutzen können du hast oben beschrieben.

+1

Ich würde auch empfehlen, diese "SELECT *" s nur zu verwenden, wenn Sie sie wirklich brauchen. Sie können Leistungsprobleme verursachen, und die meiste Zeit sind nicht wirklich notwendig. –

+0

Diese Syntax zum Erstellen der temporären Tabelle kann sich ebenfalls als nützlich erweisen: Wählen Sie * In #Recs From ... –

+0

Eigentlich habe ich eine komplexe SELECT-Anweisung, die ich auf hierarchische Daten tun muss und die Art, wie es aufgerufen wird, wird je nach Situation stark variieren. –

4

Sie könnten ein Feld anhängen, die die Summe der Zeilen in ihm hat, natürlich ist es auf jeder Zeile wird

select recs.*,totalrows = (select count(0) from recs) 
from recs 
1

Dies ist die beste:

;WITH recs AS 
(SELECT a,b,c, 
     row_number() over (
         ORDER BY id) AS RowNum, 
        row_number() over() AS RecordCount 
FROM ......) 
SELECT a,b,c,rownum,RecordCount FROM recs 
WHERE rownum BETWEEN @a AND @b 
1

Dies ist, wie Wir beschäftigen uns mit Paging (ohne Session-Management für jetzt) ​​in einer Produktionsumgebung. Funktioniert wie erwartet.

DECLARE 
    @p_PageNumberRequested int = 1, 
     -- Provide -1 to retreive all pages with all the rows. 
    @p_RowsPerPage   int = 25 

;WITH Numbered AS (
SELECT 
    ROW_NUMBER() OVER (ORDER BY YourOrdering) AbsoluteRowNumber 
, COUNT(1) OVER() TotalRows 
, YourColumns 
FROM 
    YourTable 
), 
Paged AS (
SELECT 
    (AbsoluteRowNumber - 1)/@p_RowsPerPage + 1 PageNumber, 
    * 
FROM 
    Numbered) 
SELECT 
    ROW_NUMBER() OVER(PARTITION BY PageNumber ORDER BY AbsoluteRowNumber) RowNumberOnPage, 
    * 
FROM 
    Paged 
WHERE 
     PageNumber = @p_PageNumberRequested 
    OR 
     @p_PageNumberRequested = -1 
ORDER BY 
    AbsoluteRowNumber 
Verwandte Themen