Manteniéndolo simple y cómo hacer múltiples CTE en una consulta

156

Tengo esta simple consulta T-SQL, emite un montón de columnas de una tabla y también une información de otras tablas relacionadas .

Mi modelo de datos es simple. Tengo un evento programado, con participantes. Necesito saber cuántos participantes participan en cada evento.

Mi solución a esto es agregar un CTE que agrupe los eventos programados y cuente el número de participantes.

Esto me permitirá unirme a esa información por evento programado. Manteniendo la consulta simple.

Sin embargo, me gustaría mantener mis consultas simples. Si alguna vez necesito tener resultados temporales adicionales accesibles durante mi consulta simple, ¿qué debo hacer?

Realmente me gustaría, si pudiera tener múltiples CTE pero no puedo, ¿verdad? ¿Cuáles son mis opciones aquí?

He descartado las vistas y hacer cosas en la capa de datos de la aplicación. Prefiero aislar mis consultas SQL.

John Leidegren
fuente

Respuestas:

297

Puede tener múltiples correos CTEelectrónicos en una consulta, así como reutilizar a 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

Tenga en cuenta, sin embargo, que SQL Serverpuede volver a evaluar CTEcada vez que se accede, por lo que si utiliza valores como RAND(), NEWID()etc., pueden cambiar entre las CTEllamadas.

Quassnoi
fuente
3
Fue así de simple. la documentación de MSDN era un poco confusa en torno al tema, no pude encontrar nada concluyente. ¡Muchas gracias!
John Leidegren
1
Está documentado en WITH common_table_expression (Transact-SQL) . Puede ver que esto se encuentra en la sección de sintaxis (tome nota especial de la [ ,...n ]in [ WITH <common_table_expression> [ ,...n ] ]. Ejemplo C, "Usar múltiples definiciones CTE en una sola consulta", lo llama explícitamente. Lamentablemente, este ejemplo no se proporciona en la documentación de SQL 2008 y anterior (es decir, el ejemplo no se proporcionó cuando el OP publicó la pregunta).
Brian
Obtuve el doble de registros en esto: /
Tom Stickel
@TomStickel intente usar solo la mitad de la consulta, antes de la últimaUNION ALL
Quassnoi
@Quassnoi Sí, eso funcionó. Lo hice después de escribir el comentario. No estoy seguro de por qué esa segunda unión está allí ...
Tom Stickel
90

Ciertamente puede tener múltiples CTE en una sola expresión de consulta. Solo necesita separarlos con una coma. Aquí hay un ejemplo. En el siguiente ejemplo, hay dos CTE. Uno se nombra CategoryAndNumberOfProductsy el segundo se nombra 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
fuente
55
@JohnLeidegren: publicar una respuesta correcta dentro de los 2 minutos de la primera respuesta correcta merece un voto positivo, que he dado, al menos.
Peter Majeed