ทำให้มันง่ายและวิธีการหลาย CTE ในแบบสอบถาม


156

ฉันมีแบบสอบถาม T-SQL ง่าย ๆ นี้มันปล่อยกลุ่มคอลัมน์จากตารางและรวมข้อมูลจากตารางอื่น ๆที่เกี่ยวข้อง

แบบจำลองข้อมูลของฉันง่าย ฉันมีกิจกรรมที่กำหนดไว้พร้อมผู้เข้าร่วม ฉันจำเป็นต้องรู้จำนวนผู้เข้าร่วมในแต่ละเหตุการณ์

วิธีแก้ปัญหาของฉันคือการเพิ่ม CTE ที่จัดกลุ่มกิจกรรมตามกำหนดเวลาและนับจำนวนผู้เข้าร่วม

สิ่งนี้จะทำให้ฉันเข้าร่วมในข้อมูลนั้นต่อเหตุการณ์ที่กำหนดไว้ ทำให้การสืบค้นง่ายขึ้น

ฉันต้องการที่จะทำให้การสืบค้นของฉันง่าย แต่ถ้าฉันเคยมีในอนาคตจำเป็นต้องมีผลลัพธ์ชั่วคราวเพิ่มเติมที่สามารถเข้าถึงได้ในระหว่างการสืบค้นง่ายๆฉันจะทำอย่างไร

ฉันอยากได้มันถ้าฉันมี CTE ได้หลายอัน แต่ทำไม่ได้ใช่ไหม? ตัวเลือกของฉันที่นี่มีอะไรบ้าง

ฉันตัดทอนมุมมองและทำสิ่งต่าง ๆ ในชั้นข้อมูลแอปพลิเคชัน ฉันชอบที่จะแยกแบบสอบถาม SQL ของฉัน

คำตอบ:


297

คุณสามารถมีหลายCTEs ในการค้นหาเดียวเช่นเดียวกับการใช้ซ้ำ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

แต่โปรดทราบว่าSQL ServerอาจประเมินCTEเวลาที่มีการเข้าถึงแต่ละครั้งดังนั้นถ้าคุณกำลังใช้ค่าเช่นRAND(), NEWID()ฯลฯ พวกเขาอาจมีการเปลี่ยนแปลงระหว่างCTEการโทร


3
มันง่ายมาก เอกสารของ MSDN นั้นค่อนข้างคลุมเครือในเรื่องนี้ฉันไม่สามารถหาข้อสรุปใด ๆ ได้ ขอบคุณมาก!
John Leidegren

1
มันเป็นบันทึกไว้ในกับ common_table_expression (Transact SQL) คุณสามารถดูสิ่งนี้ได้ในหัวข้อไวยากรณ์ (จดบันทึกพิเศษของ[ ,...n ]in [ WITH <common_table_expression> [ ,...n ] ]ตัวอย่าง C, "การใช้หลายคำจำกัดความ CTE ในแบบสอบถามเดียว" เรียกสิ่งนี้ออกมาอย่างชัดเจนน่าเศร้าตัวอย่างนี้ไม่มีอยู่ในเอกสารประกอบสำหรับ SQL 2008 และ เก่ากว่า (นั่นคือตัวอย่างที่ไม่ได้ให้ไว้เมื่อ OP โพสต์คำถาม)
Brian

ฉันได้รับจำนวนบันทึกสองเท่าในนี้: /
Tom Stickel

@TomStickel ลองใช้เพียงครึ่งหนึ่งของข้อความค้นหาก่อนหน้าสุดท้ายUNION ALL
Quassnoi

@Quassnoi ใช่แล้วใช้ได้ ฉันทำอย่างนั้นหลังจากเขียนความคิดเห็นแล้ว ไม่แน่ใจว่าทำไมสหภาพที่ 2 ถึงแม้จะอยู่ที่นั่น ...
Tom Stickel

90

แน่นอนคุณสามารถมี CTE หลายรายการในนิพจน์แบบสอบถามเดียว คุณเพียงแค่ต้องแยกพวกเขาด้วยเครื่องหมายจุลภาค นี่คือตัวอย่าง ในตัวอย่างด้านล่างมี CTE สองตัว หนึ่งคือการตั้งชื่อและครั้งที่สองมีชื่อว่าCategoryAndNumberOfProductsProductsOverTenDollars

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

5
@JohnLeidegren: โพสต์คำตอบที่ถูกต้องภายใน 2 นาทีจากคำตอบแรกที่ถูกต้องจะได้รับ upvote อย่างน้อยที่สุด
Peter Majeed
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.