Volver a la lista de artículos Artículos
Lectura de 18 minutos

Proyecto SQL para principiantes: Cuadro de mando de ventas AdventureWorks

Crear un proyecto SQL por su cuenta es una excelente forma de perfeccionar sus habilidades y adquirir experiencia práctica. Este ejemplo de proyecto SQL para principiantes le mostrará cómo crear un cuadro de mando de ventas con SQL y la base de datos de muestra AdventureWorks.

Si usted es un principiante en SQL que desea llevar sus habilidades más allá de simples ejercicios de consulta, es una buena idea abordar un proyecto de análisis de datos SQL. No sólo le desafiará a aplicar lo que ha aprendido, sino que también le proporcionará una comprensión más profunda de cómo funciona SQL en escenarios del mundo real. Esta es tu oportunidad de pasar de la práctica básica a la creación de algo tangible que muestre tu creciente experiencia.

En este artículo, te guiaremos a través de los pasos para crear un proyecto SQL utilizando la base de datos AdventureWorks. Cubriremos todo, desde la idea del proyecto hasta la escritura de las consultas finales. Aprenderás cómo abordar cada paso del proceso, y los conceptos que utilizaremos pueden transferirse a cualquier proyecto SQL.

Una vez que hayas terminado, echa un vistazo a nuestro curso Bases de datos SQL para la práctica, que cuenta con 6 bases de datos diferentes para que practiques creando informes. También puedes leer cómo encontrar conjuntos de datos gratuitos para tu propio proyecto SQL y seguir con tu propia base de datos.

Ahora, echemos un vistazo a la base de datos que utilizaremos en este proyecto SQL de ejemplo.

Explorando la Base de Datos AdventureWorks

La base de datos AdventureWorks es una base de datos de ejemplo creada por Microsoft para SQL Server. Ha sido portado a muchas bases de datos - incluyendo PostgreSQL, la cual usaremos en este artículo. La base de datos incluye 68 tablas que describen a un fabricante ficticio de bicicletas y contiene datos sobre diferentes tipos de transacciones que ocurren durante las operaciones comerciales. Como AdventureWorks es tan grande, es un conjunto de datos perfecto para principiantes que quieran practicar SQL en un entorno real.

La base de datos está dividida en 5 esquemas, cada uno de los cuales representa un campo de operaciones diferente: Production, Purchasing, Sales, HR, y Person. En este proyecto, la mayoría de nuestros datos procederán del Sales . También utilizaremos otros esquemas para obtener información adicional.

Veamos las tablas que más utilizaremos:

: Cuadro de mando de ventas de AdventureWorks
  • SalesOrderHeader: Esta es la tabla más grande de la base de datos. Almacena toda la información relativa a un pedido en su conjunto. Será el punto de partida más común para las consultas relacionadas con las ventas.
  • Product: En ella se almacena amplia información sobre los productos que ofrece la empresa.
  • SalesOrderDetail: Esta tabla conecta los SalesOrderHeader y Product almacenando información sobre los productos individuales que componen cada pedido.
  • ProductReview: Almacena las opiniones de los clientes sobre productos específicos.
  • Store: Esta tabla almacena información básica sobre cada tienda. La mayoría de los datos se almacenan en la columna Demographics en formato XML; no la utilizaremos en este proyecto.
  • SalesTerritory y CountryRegion: Utilizaremos estas dos tablas juntas para obtener el nombre del país al que está asociado el pedido.

Hay muchas otras tablas en la base de datos, pero no se preocupe; iremos introduciéndolas y sus columnas importantes a medida que sea necesario.

Especificación del proyecto SQL

En este proyecto, queremos construir un tablero de ventas para AdventureWorks. Pero, ¿cómo empezamos un proyecto como éste? Un buen punto de partida es determinar el alcance del proyecto. A menudo, esto significa crear una lista de preguntas que desea responder con los datos. Nuestra lista inicial de preguntas es

  • ¿Cuáles son las ventas mensuales totales?
  • ¿Cuáles son las ventas mensuales por país?
  • ¿Qué productos son los más vendidos?
  • ¿Qué tiendas funcionan mejor?
  • ¿Cuál es el volumen medio de cada pedido?
  • ¿Cuál es el valor medio del ciclo de vida del cliente en cada país?

A medida que nos sumergimos en los datos y escribimos nuestras consultas, podemos refinar estas preguntas y ajustar nuestras consultas en consecuencia.

Así es como deberías empezar todos tus proyectos SQL: escribe una lista de las preguntas que tienes para los datos y luego escribe las consultas que te darán las respuestas. A medida que trabajes con las consultas y los datos, surgirán nuevas preguntas. Intenta responderlas también con tus consultas.

Ahora estamos listos para empezar a escribir las consultas para nuestro panel de ventas. Tenga a mano nuestra hoja de ayudaSQL para principiantes en caso de que necesite un rápido repaso de la sintaxis.

¿Qué incluiremos en nuestro Tablero de Proyecto SQL?

Informe 1: Ventas Mensuales

Pregunta: ¿Cuáles son los ingresos mensuales de la empresa?

El primer informe de nuestro cuadro de mandos muestra los ingresos de todos los meses anteriores (de todos los años). Esta consulta se puede utilizar para trazar líneas de tendencia de los ingresos, o se puede analizar tal cual. Queremos ver los datos en orden cronológico, empezando por las fechas más recientes.

Enfoque

En primer lugar, elegimos la tabla en la que se basará nuestra consulta. Queremos mostrar tres columnas: el año y el mes de la venta y los ingresos totales de ese mes y ese año. Necesitamos el importe total del pedido y la fecha de venta, por lo que la tabla SalesOrderHeader del esquema Sales es una opción obvia.

Para mostrar el año y el mes, utilizaremos la función EXTRACT:

EXTRACT(<MONTH / YEAR> FROM OrderDate)

Utilizaremos estas columnas al agrupar y ordenar el resultado.

Para obtener los ingresos totales de ese mes concreto, podemos utilizar SUM(TotalDue) junto con la agrupación por las dos columnas anteriores. Esto nos llevará a tener resultados SUM() separados para cada par año-mes único.

Esta es la consulta final:

SELECT
  EXTRACT(YEAR FROM OrderDate) AS OrderYear,
  EXTRACT(MONTH FROM OrderDate) AS OrderMonth,
  ROUND(SUM(TotalDue), 2) AS TotalRevenue
FROM Sales.SalesOrderHeader
GROUP BY 
  EXTRACT(YEAR FROM OrderDate),
  EXTRACT(MONTH FROM OrderDate)
ORDER BY 
  OrderYear DESC,
  OrderMonth DESC;

Informe 2: Ingresos mensuales por país

Pregunta: ¿Cuáles son los ingresos mensuales de cada país?

Queremos ver los ingresos totales de cada mes (de cada año) para cada país de la base de datos. El resultado debe ordenarse cronológicamente, con las fechas más recientes en primer lugar. Podemos utilizar estos datos para trazar líneas de tendencia para cada país o analizar los datos tal cual.

Enfoque

Esta consulta es similar a la anterior: sólo tenemos que añadir información sobre el país para cada compra. ¿Cómo podemos hacerlo?

La tabla SalesOrderHeader tiene una columna llamada TerritoryId, que hace referencia a la tabla SalesTerritory tabla. Esta tabla nos da acceso a la columna CountryRegionCode.

Los nombres de los países se almacenan en la tabla CountryRegion del Person del esquema. Podemos unir esta tabla a la tabla SalesTerritory utilizando el código de región. Esto nos deja una forma clara de ampliar nuestra consulta.

Si unimos las tablas de la siguiente manera: SalesOrderHeader -> SalesTerritory -> CountryRegion, tendremos acceso a la columna CountryRegion.Name. Podemos añadirla como primera columna en la sentencia SELECT y añadirla al final de las sentencias GROUP BY y ORDER BY.

Eche un vistazo a la consulta final:

SELECT
  cr.Name AS Country,
  EXTRACT(YEAR FROM OrderDate) AS OrderYear,
  EXTRACT(MONTH FROM OrderDate) AS OrderMonth,
  ROUND(SUM(TotalDue), 2) AS TotalRevenue
FROM Sales.SalesOrderHeader soh
JOIN Sales.SalesTerritory st
  ON soh.TerritoryId = st.TerritoryId
JOIN Person.CountryRegion cr
  ON cr.CountryRegionCode = st.CountryRegionCode
GROUP BY 
  cr.Name,
  EXTRACT(YEAR FROM OrderDate),
  EXTRACT(MONTH FROM OrderDate)
ORDER BY
  OrderYear DESC,
  OrderMonth DESC,
  Country;

He aquí una parte del resultado:

CountryOrderYearOrderMonthTotalRevenue
Australia201469958.82
Canada2014611471.62
France201463660.88
Germany201463818.44

Informe 3: Productos más vendidos

Pregunta: ¿Cuáles son nuestros productos más vendidos?

Nos gustaría añadir una lista de los productos más vendidos junto con alguna información relevante como las ventas de toda la vida y las opiniones de los clientes. El informe debe mostrar datos razonablemente recientes.

Enfoque

La tabla SalesOrderDetail que contiene la cantidad de cada artículo vendido, será nuestro punto de partida para esta consulta. La iremos construyendo poco a poco.

La métrica principal de esta consulta es la cantidad total vendida de cada producto, que podemos obtener utilizando la combinación de SUM(OrderQty) y GROUP BY ProductId.

Sin embargo, el resultado de la consulta sería bastante difícil de leer, ya que los productos sólo son identificables por su Id. Los nombres de los productos se almacenan en la tabla Product del esquema Production esquema. Uniendo las dos tablas mediante ProductId y añadiendo ProductName obtenemos esta consulta:

SELECT
  p.ProductId,
  p.Name AS ProductName,
  SUM(od.OrderQty) AS TotalUnitsSold
FROM Sales.SalesOrderDetail od
JOIN Production.Product p
  ON od.ProductID = p.ProductID
GROUP BY
  p.Name,
  p.ProductId
ORDER BY TotalUnitsSold DESC
LIMIT 10;
ProductIdProductNameTotalUnitsSold
712AWC Logo Cap8311
870Water Bottle - 30 oz.6815

Esta consulta es un elemento viable del cuadro de mando, pero puede mejorarse.

Ya hemos sentado las bases para trabajar con productos. Ahora, queremos añadir las valoraciones a nuestros productos. Vamos a construirlo como una consulta separada, que luego uniremos con la consulta principal.

Las valoraciones de los productos se almacenan en la tabla ProductReview de la tabla Production esquema. Nos interesan principalmente ProductId y Rating dejadas por el cliente, así que promediaremos las puntuaciones de las valoraciones y agruparemos los datos por ProductId.

Ahora tenemos una correspondencia unívoca entre el producto y sus valoraciones. Vamos a redondear el resultado a un decimal, como es habitual en las revisiones:

SELECT
  ProductId,
  ROUND(AVG(Rating), 1) AS ProductRating
FROM Production.ProductReview
GROUP BY ProductId;
ProductIdProductRating
9373.0
7985.0
7095.0

Ahora podemos envolver esta consulta en una expresión común de tabla (CTE) para utilizarla junto con nuestra consulta principal. Las CTE son una forma de crear un conjunto de resultados temporal, como una tabla virtual que sólo existe en el contexto de la consulta. Si quieres una explicación completa de cómo funcionan las CTEs, consulta nuestra guía completa sobre CTEs en SQL.

Ahora bien, aquí hay un posible problema: puede que no haya reseñas para todos los productos. Por lo tanto, cuando unimos Product de la consulta principal con la CTE, asegúrese de utilizar LEFT JOIN para no perder ningún dato.

Podría ser beneficioso mirar sólo los datos más recientes. Podemos filtrar las ventas antiguas en la consulta principal utilizando la columna OrderDate y restar dos meses de la fecha actual utilizando INTERVAL ‘2 MONTHS’. Entonces podemos filtrar los datos para mostrar sólo los pedidos realizados después de esa fecha.

Si decide cambiar el intervalo de fechas, modificar la parte INTERVAL es bastante sencillo. Para aprender más sobre la sintaxis de INTERVAL, eche un vistazo a nuestro curso Funciones estándar de SQL .

Esta es la consulta completa:

WITH ProductRating AS (
  SELECT
    ProductId,
    ROUND(AVG(Rating), 1) AS ProductRating
  FROM Production.ProductReview
  GROUP BY ProductId
)
SELECT
  p.ProductId,
  p.Name AS ProductName,
  SUM(od.OrderQty) AS TotalUnitsSold,
  pr.ProductRating AS ProductRating
FROM Sales.SalesOrderDetail od
JOIN Sales.SalesOrderHeader oh
  ON od.SalesOrderId = oh.SalesOrderId
JOIN Production.Product p
  ON od.ProductID = p.ProductID
LEFT JOIN ProductRating pr
  ON pr.ProductId = p.ProductId
WHERE OrderDate > CURRENT_DATE - INTERVAL '2 MONTH'
GROUP BY
  p.Name,
  p.ProductId,
  pr.ProductRating
ORDER BY TotalUnitsSold DESC
LIMIT 10;
ProductIdProductNameTotalUnitsSoldProductRating
921Mountain Tire Tube187N/A
873Patch Kit / 8 Patches181N/A
870Water Bottle - 30 oz.168N/A
922Road Tire Tube160N/A
878Fender Set - Mountain107N/A
711Sport-100 Helmet, Blue96N/A
712AWC Logo Cap95N/A
708Sport-100 Helmet, Black93N/A
923Touring Tire Tube91N/A
871Mountain Bottle Cage84N/A

Ésta sí que es una lista digna de aparecer en el panel de control de un representante. Conocer las tendencias de ventas es algo a lo que todos los empleados deberían tener acceso, y ahora tenemos una consulta que nos lo ofrece.

Nuestro cuadro de mandos está creciendo; ¡añadamos algunas métricas más!

Informe 4: Tiendas con mejores resultados

Pregunta: ¿Cuáles son las 10 tiendas que más han vendido en los últimos 2 meses?

Nos gustaría mostrar las diez principales tiendas -incluidas las tiendas en línea- y su respectivo aumento de ingresos en los últimos dos meses. Una "tienda líder" se define como la que más ingresos ha obtenido en los últimos 2 meses. Trate todas las tiendas en línea como una sola entidad.

Enfoque

Como de costumbre, empezaremos con la tabla SalesOrderHeader tabla. Para saber qué tienda es responsable de qué venta, echemos un vistazo a la tabla Store en el esquema Sales esquema.

Cada tienda puede vincularse a una venta a través de la columna SalesPersonId. Todas las ventas en las que SalesPersonId es NULL también tienen su OnlineOrderFlag establecido en true. Esto facilitará el trabajo de agrupar y mostrar las ventas en línea, ya que podemos tratar cualquier venta en la que SalesPersonId sea NULL como una venta en línea.

Para no perder datos al unir las tablas en SalesPersonId (que a veces es NULL), utilice un LEFT JOIN entre SalesOrderHeader y Tienda. En la sentencia SELECT, nos importan dos cosas: el nombre de la tienda y el total de ventas realizadas en esa tienda. No olvide envolver la columna Store.Name con COALESCE(..., ‘Online’) para asegurarse de que todos los pedidos en línea tengan una etiqueta legible.

Para filtrar los datos antiguos, utilice la misma condición WHERE que en el último informe:

WHERE OrderDate > CURRENT_DATE - INTERVAL ‘2 MONTHS’.

Ordene los resultados por el importe total de las ventas (mostrando primero los valores más grandes) y utilice LIMIT 10 para devolver sólo las 10 tiendas principales por ingresos en el periodo seleccionado.

Esta es la consulta:

SELECT
  COALESCE(s.Name, 'Online') AS StoreName,
  ROUND(SUM(so.TotalDue), 2) AS TotalSalesAmount
FROM Sales.SalesOrderHeader so
LEFT JOIN Sales.Store s
  ON so.SalesPersonId = s.SalesPersonId
WHERE OrderDate > CURRENT_DATE - INTERVAL '2 MONTHS'
GROUP BY s.Name
ORDER BY TotalSalesAmount DESC
LIMIT 10;
StoreNameTotalSalesAmount
Online2419079.86
Friendly Bike Shop577136.64
Exceptional Cycles Services495918.62
Number One Bike Co.495918.62

Informe 5: Fuentes de ingresos

Pregunta: ¿Cómo se comparan los ingresos en línea con los ingresos fuera de línea?

Para esta métrica del cuadro de mando, nos gustaría incluir datos sobre cuántos pedidos se realizaron en línea frente a los realizados en una tienda. Los resultados finales deberían desglosarse por mes y año.

Enfoque

Una vez más, construiremos esta consulta de forma iterativa. Para dividir las ventas en grupos en línea y fuera de línea, podemos utilizar la dirección OnlineOrderFlag de la tabla Sales.SalesOrderHeader de la tabla. Esta tabla también incluye convenientemente el precio total del pedido, por lo que esta métrica puede calcularse a partir de una sola tabla.

Sin embargo, OnlineOrderFlag es un dato de tipo BOOLEAN; si lo utilizamos en la cláusula GROUP BY nos quedaremos con los grupos true y false. Para que los datos sean más legibles, podemos utilizar una expresión CASE WHEN para sustituir todos los verdaderos por "Online" y todos los falsos por "Store". Y como OnlineOrderFlag ya evalúa a BOOLEAN, no necesitamos modificarla para utilizarla como condición. Para una explicación más detallada sobre cómo estamos utilizando CASE WHEN en este ejemplo, lea nuestra guía sobre cómo utilizar CASE WHEN con GROUP BY.

Ahora que tenemos los nombres de grupo adecuados, podemos seleccionar las otras métricas que comparan las fuentes de ingresos: el número total de acuerdos cerrados y los ingresos totales de esos acuerdos. Puede encontrar el primero simplemente contando todos los SalesOrderIds y el segundo sumando todos los valores de TotalDue. La agrupación puede realizarse utilizando OnlineOrderFlag y no la expresión CASE WHEN; en este caso, simplemente estamos asignando valores.

Este es el aspecto de la consulta actual:

SELECT
  CASE WHEN OnlineOrderFlag THEN 'Online' ELSE 'Store' END AS OrderOrigin,
  COUNT(SalesOrderId) AS TotalSales,
  SUM(TotalDue) AS TotalRevenue
FROM Sales.SalesOrderHeader
GROUP BY OnlineOrderFlag
ORDER BY TotalRevenue DESC;
OrderOriginTotalSalesTotalRevenue
Online276593244139
Store380690775446

Podemos ver claramente una conclusión: Las tiendas físicas realizan casi 10 veces menos ventas pero producen 3 veces más ingresos que la tienda online.

Podemos hacer que estos datos sean más significativos filtrándolos por año y mes para poder ver las tendencias en los flujos de ingresos. La tabla Sales.SalesOrderHeader tabla incluye la columna OrderDate, que podemos utilizar para obtener sólo las partes YEAR y MONTH como hicimos en el primer informe. Si añadimos esto como columnas adicionales y las utilizamos en GROUP BY, veremos que los grupos “Store” y “Online” se han dividido en diferentes años y meses. Podemos filtrar adicionalmente las fechas, como hicimos antes con CURRENT_DATE y INTERVAL.

Aquí está la consulta completa y una muestra de los resultados:

SELECT
  CASE WHEN OnlineOrderFlag THEN 'Online' ELSE 'Store' END AS OrderOrigin,
  EXTRACT(YEAR FROM OrderDate) AS OrderYear,
  EXTRACT(MONTH FROM OrderDate) AS OrderMonth,
  COUNT(SalesOrderId) AS TotalSales,
  SUM(TotalDue) AS totalRevenue
FROM Sales.SalesOrderHeader
WHERE OrderDate > CURRENT_DATE - INTERVAL '2 MONTHS'
GROUP BY
  EXTRACT(YEAR FROM OrderDate),
  EXTRACT(MONTH FROM OrderDate),
  OnlineOrderFlag
ORDER BY
  OrderOrigin,
  OrderYear DESC,
  OrderMonth DESC;
OrderOriginOrderYearOrderMonthTotalSalesTotalRevenue
Online2014693954151,48
Store20145125843850111,69
Online201454062156071,52
Store2014421428,61

Informe 6: Tamaño medio de los pedidos por país

Pregunta: ¿Cuál es el tamaño medio de los pedidos?

Nos gustaría mostrar cada país y el tamaño medio de los pedidos de todos los pedidos procedentes de ese país. Los países con mayor volumen medio de pedidos deben mostrarse en primer lugar.

Enfoque

Ya hemos obtenido el nombre del país para cada venta en uno de los informes anteriores, así que podemos centrarnos en el tamaño de los pedidos. Es importante tener en cuenta que tendremos que agregar dos veces en esta consulta: Primero para obtener el tamaño de cada pedido y luego para obtener el promedio por país. Empezaremos por obtener los tamaños de los pedidos.

Cada pedido puede identificarse mediante una entrada en la tabla SalesOrderHeader de la tabla. Tendrá varias entradas respectivas en la tabla SalesOrderDetail tabla correspondientes a cada producto del pedido. Si sumamos los OrderQtys de la tabla SalesOrderDetail tabla para cada SalesOrderId nos deja pares ordenados de número_pedido-tamaño_pedido.

Utilizaremos un par de JOINs para obtener los nombres de los países, formando un CTE como éste:

WITH OrderSizes AS (
  SELECT
    sod.SalesOrderId,
    SUM(OrderQty) AS ProductCount,
    cr.Name AS Country
  FROM Sales.SalesOrderHeader soh
  JOIN Sales.SalesOrderDetail sod
    ON sod.SalesOrderId = soh.SalesOrderId
  JOIN Sales.SalesTerritory st
    ON soh.TerritoryId = st.TerritoryId
  JOIN Person.CountryRegion cr
    ON cr.CountryRegionCode = st.CountryRegionCode
  GROUP BY
    sod.SalesOrderId,
    cr.Name
)
SELECT * 
FROM OrderSizes;

Ahora sólo es cuestión de obtener el tamaño medio de los pedidos a partir del CTE y agrupar el resultado por países. No olvides ordenar los datos para mostrar primero los pedidos de mayor tamaño medio.

Eche un vistazo a la consulta completa y a su resultado parcial:

WITH OrderSizes AS (
  SELECT
    sod.SalesOrderId,
    SUM(OrderQty) AS ProductCount,
    cr.Name AS Country
  FROM Sales.SalesOrderHeader soh
  JOIN Sales.SalesOrderDetail sod
    ON sod.SalesOrderId = soh.SalesOrderId
  JOIN Sales.SalesTerritory st
    ON soh.TerritoryId = st.TerritoryId
  JOIN Person.CountryRegion cr
    ON cr.CountryRegionCode = st.CountryRegionCode
  GROUP BY
    sod.SalesOrderId,
    cr.Name
)
SELECT
  Country,
  ROUND(AVG(ProductCount), 2) AS AverageOrderSize
FROM OrderSizes
GROUP BY Country
ORDER BY AverageOrderSize DESC;
CountryAverageOrderSize
United States12.80
Canada12.14
France7.45
United Kingdom6.24
Germany5.01
Australia2.67

Informe 6: Valor medio del cliente durante su vida útil por región

Pregunta: ¿Cuál es el valor medio de vida del cliente en cada región?

El valor del ciclo de vida del cliente (CLV) es una métrica importante que muestra cuánto puede esperar la empresa que gaste un cliente recién adquirido durante toda su relación con la marca. El CLV se calcula sumando los ingresos de todas las compras del cliente. Es muy útil para calcular el presupuesto de las campañas de marketing; se muestra mejor agrupado por la región de operaciones.

Enfoque

Primero vamos a crear la consulta que calcula el CLV medio de cada cliente individualmente. Ya sabemos cómo se calcula el CLV: sumando todos los valores de TotalDue para cada cliente de la tabla SalesOrderHeader de la tabla. Esto nos dará un resultado intermedio. Más adelante queremos agruparlo por países, por lo que es conveniente incluir aquí también algunos de esos datos.

La tabla Customer en el mismo esquema tiene una columna TerritoryId, que podemos utilizar más adelante para obtener más información. De momento, vamos a añadir TerritoryId a la consulta CLV como columna adicional. Esto requiere una simple unión y una ampliación de la sentencia GROUP BY.

Este es el aspecto de la consulta hasta ahora, junto con algunos resultados de ejemplo:

SELECT
  cs.CustomerId,
  cs.TerritoryId,
  SUM(TotalDue) AS LifetimeRevenues
FROM sales.Customer cs
JOIN sales.SalesOrderheader ord
  ON cstm.CustomerId = ord.CustomerId
GROUP BY
  cs.CustomerId,
  cs.TerritoryId;
CustomerIdTerritoryIdLifetimeRevenue
26264434.56
30052421863.90
244161106.16
2674592135.37

La mitad del problema está resuelto. Lo que queda es agrupar esto a nivel de país y hacer que el resultado sea más legible. Utilicemos un CTE para guardar los resultados de esta consulta.

Podemos agrupar el CTE por TerritoryId y mostrar el valor medio de vida de los clientes por territorio. Esto da un resultado técnicamente correcto, aunque los territorios no son identificables. Los nombres reales de los países se almacenan en la tabla CountryRegion de la tabla Person esquema. Es identificable por la clave CountryRegionCode. En el Sales podemos encontrar esa clave en la tabla SalesTerritory tabla. Así, uniremos el resultado de la CTE, a través de la tabla SalesTerritory con la tabla CountryRegion tabla. Ahora podemos mostrar el nombre del país en lugar de su numérico Id. No olvides editar el GROUP BY en consecuencia.

Echa un vistazo a la consulta final y a algunos de sus resultados:

WITH CustomerLifetimeRevenue AS (
  SELECT
    cstm.CustomerId,
    ord.TerritoryId,
    SUM(TotalDue) AS LifetimeRevenue
  FROM Sales.Customer cstm
  JOIN Sales.SalesOrderHeader ord
    ON cstm.CustomerId = ord.CustomerId
  GROUP BY
    cstm.CustomerId,
    ord.TerritoryId
)
SELECT
  cr.Name AS Country,
  ROUND(AVG(clr.LifetimeRevenue),2) AS AvgLifetimeCustomerValue
FROM CustomerLifetimeRevenue clr
JOIN Sales.SalesTerritory tr
  ON clr.TerritoryId = tr.TerritoryId
JOIN Person.CountryRegion cr
  ON cr.CountryRegionCode = tr.CountryRegionCode
GROUP BY cr.Name
ORDER BY
  AvgLifetimeCustomerValue DESC,
  cr.Name;
CountryAvgLifetimeCustomerValue
Canada10971.34
United States8627.27
France4403.33
United Kingdom4394.69
Australia3259.14
Germany3024.18

¡Cree su Propio Proyecto SQL para Principiantes!

Hemos creado exitosamente consultas que pueden alimentar un tablero de ventas informativo. Sin embargo, el objetivo de este artículo es inspirarle para que inicie su propio proyecto SQL. Recapitulemos cómo crear un proyecto SQL:

  • Encuentre un conjunto de datos interesante.
  • Plantee un problema de negocio para este conjunto de datos, como hicimos con este cuadro de mando de ventas.
  • Escriba preguntas relacionadas con el problema que el proyecto ayudará a responder.
  • Construye consultas SQL para las preguntas que has escrito.

Si necesitas un poco más de estructura, te recomendamos nuestro mini-curso Bases de Datos SQL para la Práctica. Contiene 6 bases de datos diferentes que puedes utilizar en tu propio proyecto SQL, así como algunas preguntas y sugerencias para empezar.

Si quieres ver más ejemplos de proyectos SQL para principiantes, echa un vistazo a nuestro artículo sobre cómo crear un proyecto de tienda Northwind para tu portfolio.

¿Tienes hambre de más práctica general? Echa un vistazo a nuestro enorme Ejercicio de SQL Track. ¡Feliz aprendizaje!