Halten Sie es einfach und wie Sie mehrere CTE in einer Abfrage durchführen

156

Ich habe diese einfache T-SQL-Abfrage, sie gibt eine Reihe von Spalten aus einer Tabelle aus und verknüpft auch Informationen aus anderen verwandten Tabellen.

Mein Datenmodell ist einfach. Ich habe eine geplante Veranstaltung mit Teilnehmern. Ich muss wissen, wie viele Teilnehmer an jeder Veranstaltung teilnehmen.

Meine Lösung besteht darin, einen CTE hinzuzufügen, der geplante Ereignisse gruppiert und die Anzahl der Teilnehmer zählt.

Auf diese Weise kann ich diese Informationen pro geplantem Ereignis eingeben. Die Abfrage einfach halten.

Ich möchte meine Abfragen jedoch einfach halten. Was kann ich tun, wenn ich in Zukunft während meiner einfachen Abfrage zusätzliche temporäre Ergebnisse haben muss?

Ich würde es wirklich mögen, wenn ich mehrere CTEs haben könnte, aber ich kann nicht, oder? Welche Möglichkeiten habe ich hier?

Ich habe Ansichten und Aktionen auf der Anwendungsdatenebene ausgeschlossen. Ich bevorzuge es, meine SQL-Abfragen zu isolieren.

John Leidegren
quelle

Antworten:

297

Sie können mehrere CTEs in einer Abfrage haben und Folgendes wiederverwenden CTE:

WITH    cte1 AS
        (
        SELECT  1 AS id
        ),
        cte2 AS
        (
        SELECT  2 AS id
        )
SELECT  *
FROM    cte1
UNION ALL
SELECT  *
FROM    cte2
UNION ALL
SELECT  *
FROM    cte1

Beachten Sie jedoch, dass SQL Serverdie neu bewerten kann CTEjedes Mal auf sie zugegriffen wird, also wenn Sie Werte verwenden wie RAND(), NEWID()usw., können sie zwischen den ändern CTEAnrufe.

Quassnoi
quelle
3
So einfach war das. Die MSDN-Dokumentation war etwas verschwommen, ich konnte nichts aussagekräftiges finden. Vielen Dank!
John Leidegren
1
Es ist in WITH common_table_expression (Transact-SQL) dokumentiert . Sie können dies im Syntaxabschnitt sehen (beachten Sie insbesondere das [ ,...n ]in [ WITH <common_table_expression> [ ,...n ] ]. Beispiel C, "Verwenden mehrerer CTE-Definitionen in einer einzelnen Abfrage", ruft dies explizit auf. Leider ist dieses Beispiel in der Dokumentation für SQL 2008 und nicht enthalten älter (dh das Beispiel wurde nicht bereitgestellt, als das OP die Frage stellte).
Brian
Ich bekomme doppelt so viele Datensätze: /
Tom Stickel
@ TomStickel versuchen Sie nur die Hälfte der Abfrage vor dem letztenUNION ALL
Quassnoi
@ Quassnoi Ja das hat funktioniert. Ich habe das getan, nachdem ich den Kommentar geschrieben habe. Ich bin mir nicht sicher, warum diese 2. Gewerkschaft überhaupt da ist ...
Tom Stickel
89

Sie können sicherlich mehrere CTEs in einem einzigen Abfrageausdruck haben. Sie müssen sie nur durch ein Komma trennen. Hier ist ein Beispiel. Im folgenden Beispiel gibt es zwei CTEs. Einer wird benannt CategoryAndNumberOfProductsund der zweite wird benannt ProductsOverTenDollars.

WITH CategoryAndNumberOfProducts (CategoryID, CategoryName, NumberOfProducts) AS
(
   SELECT
      CategoryID,
      CategoryName,
      (SELECT COUNT(1) FROM Products p
       WHERE p.CategoryID = c.CategoryID) as NumberOfProducts
   FROM Categories c
),

ProductsOverTenDollars (ProductID, CategoryID, ProductName, UnitPrice) AS
(
   SELECT
      ProductID,
      CategoryID,
      ProductName,
      UnitPrice
   FROM Products p
   WHERE UnitPrice > 10.0
)

SELECT c.CategoryName, c.NumberOfProducts,
      p.ProductName, p.UnitPrice
FROM ProductsOverTenDollars p
   INNER JOIN CategoryAndNumberOfProducts c ON
      p.CategoryID = c.CategoryID
ORDER BY ProductName
Randy Minder
quelle
5
@JohnLeidegren: Das Posten einer korrekten Antwort innerhalb von 2 Minuten nach der ersten richtigen Antwort verdient eine positive Bewertung, die ich zumindest gegeben habe.
Peter Majeed