Menjaga agar tetap sederhana dan cara melakukan beberapa CTE dalam kueri

156

Saya punya query T-SQL sederhana ini, ia memancarkan sekelompok kolom dari sebuah tabel dan juga menggabungkan informasi dari tabel terkait lainnya .

Model data saya sederhana. Saya memiliki acara yang dijadwalkan, dengan peserta. Saya perlu tahu berapa banyak peserta yang berpartisipasi dalam setiap acara.

Solusi saya untuk ini adalah menambahkan CTE yang mengelompokkan acara yang dijadwalkan dan menghitung jumlah peserta.

Ini akan memungkinkan saya untuk bergabung dalam informasi itu per acara yang dijadwalkan. Menjaga kueri tetap sederhana.

Saya ingin menjaga pertanyaan saya tetap sederhana, namun, jika saya di masa depan perlu memiliki hasil sementara tambahan yang dapat diakses selama permintaan sederhana saya, apa yang harus saya lakukan?

Saya akan sangat menyukainya, jika saya bisa memiliki beberapa CTE tetapi saya tidak bisa, kan? Apa pilihan saya di sini?

Saya telah mengesampingkan pandangan dan melakukan hal-hal di lapisan data aplikasi. Saya lebih suka mengisolasi kueri SQL saya.

John Leidegren
sumber

Jawaban:

297

Anda dapat memiliki beberapa CTEs dalam satu permintaan, serta menggunakan kembali 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

Catatan, bagaimanapun, yang SQL Serverdapat mengevaluasi kembali CTEsetiap kali diakses, jadi jika Anda menggunakan nilai seperti RAND(), NEWID()dll, mereka dapat berubah di antara CTEpanggilan.

Quassnoi
sumber
3
Sesederhana itu. dokumentasi MSDN agak kabur tentang masalah ini, saya tidak dapat menemukan sesuatu yang konklusif. Terima kasih banyak!
John Leidegren
1
Ini didokumentasikan dalam DENGAN common_table_expression (Transact-SQL) . Anda dapat melihat ini ada di bagian sintaks (perhatikan khusus [ ,...n ]dalam [ WITH <common_table_expression> [ ,...n ] ]. Contoh C, "Menggunakan beberapa definisi CTE dalam satu permintaan," sebut ini secara eksplisit. Sayangnya, contoh ini tidak disediakan dalam dokumentasi untuk SQL 2008 dan lebih tua (yaitu, contoh tidak diberikan ketika OP memposting pertanyaan)
Brian
Saya mendapatkan dua kali lipat jumlah catatan pada ini: /
Tom Stickel
@ Tomstickel coba gunakan hanya setengah dari kueri, sebelum yang terakhirUNION ALL
Quassnoi
@ Quassnoi Ya itu berhasil. Saya telah melakukan itu setelah menulis komentar. Tidak yakin mengapa penyatuan kedua itu ada di sana ...
Tom Stickel
90

Anda tentu dapat memiliki beberapa CTE dalam ekspresi kueri tunggal. Anda hanya perlu memisahkannya dengan koma. Berikut ini sebuah contoh. Dalam contoh di bawah ini, ada dua CTE. Satu dinamai CategoryAndNumberOfProductsdan yang kedua dinamai 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
sumber
5
@JohnLeidegren: memposting jawaban yang benar dalam waktu 2 menit dari jawaban yang benar pertama layak mendapat upvote, yang saya berikan, setidaknya.
Peter Majeed