Skip to content

Queries SQL

Mindset & Code edited this page Aug 18, 2026 · 3 revisions

Queries SQL

🇬🇧 English first · 🇪🇸 Español más abajo.

The five queries in sales_analysis.sql, exactly as they are in the repository. They all run against a single table, sales_data, loaded from sales_data.csv.

Loading the data

sqlite3 sales.db
.mode csv
.import sales_data.csv sales_data
.read sales_analysis.sql

1 — Revenue and margin by region

SELECT
    Region,
    SUM(Revenue) AS Total_Revenue,
    SUM(Profit) AS Total_Profit,
    (SUM(Profit) * 100.0 / SUM(Revenue)) AS Profit_Margin_Percentage
FROM sales_data
GROUP BY Region
ORDER BY Total_Profit DESC;

Note the * 100.0 rather than * 100. In SQLite an integer division would truncate the ratio to zero before the multiplication ever happened; the decimal point forces floating-point arithmetic. It is the kind of detail that silently returns a column of zeros.

Returns 4 rows. North America leads on both revenue and profit. The margin column lands between 58,5% and 60,7% for every region — see Dataset y resultados for why that spread is noise and not a finding.


2 — Top 5 salespeople by revenue

SELECT
    SalesPersonID,
    SUM(Revenue) AS Total_Revenue
FROM sales_data
GROUP BY SalesPersonID
ORDER BY Total_Revenue DESC
LIMIT 5;

Returns 5 rows out of 20 salespeople. The dataset only carries an ID, not a name — there is no salesperson column to join against.

For SQL Server, LIMIT 5 becomes SELECT TOP 5.


3 — Customer distribution by product category

SELECT
    ProductCategory,
    CustomerType,
    COUNT(SaleID) AS Number_of_Sales
FROM sales_data
GROUP BY ProductCategory, CustomerType
ORDER BY ProductCategory, Number_of_Sales DESC;

Returns 9 rows — three categories × three customer types. The ORDER BY on two keys is what makes it readable: categories stay grouped, and inside each one the customer types come out ranked.


4 — Monthly sales trend

SELECT
    strftime('%Y-%m', SaleDate) AS Sales_Month,
    SUM(Revenue) AS Monthly_Revenue
FROM sales_data
GROUP BY Sales_Month
ORDER BY Sales_Month;

Returns 12 rows, one per month of 2024. This is the query to feed a line chart in Power BI or Tableau.

strftime is SQLite-only. On PostgreSQL use TO_CHAR(SaleDate, 'YYYY-MM'), on MySQL DATE_FORMAT(SaleDate, '%Y-%m').

Because the dates are drawn uniformly across the year, the twelve values come out essentially flat. A real book of business would not.


5 — Categories with low average profit

SELECT
    ProductCategory,
    AVG(Revenue) AS Avg_Revenue,
    AVG(Cost) AS Avg_Cost,
    AVG(Profit) AS Avg_Profit
FROM sales_data
GROUP BY ProductCategory
HAVING AVG(Profit) < 1000;

Returns 0 rows. The three categories average between 1.470 and 1.543 in profit, so none clears the threshold. That is the query working as written, not a bug — and it is the useful illustration of what HAVING does: it filters after the aggregation, on the aggregate itself, which a WHERE cannot do.


🇪🇸 Español

Las cinco consultas de sales_analysis.sql, exactamente como están en el repositorio. Todas atacan una sola tabla, sales_data, cargada desde sales_data.csv.

Cargar los datos

Ver el bloque de arriba: sqlite3 sales.db, después .mode csv, .import sales_data.csv sales_data y .read sales_analysis.sql.


1 — Ingreso y margen por región

Devuelve 4 filas. North America encabeza tanto el ingreso como el beneficio.

Fíjate en el * 100.0 en lugar de * 100. En SQLite una división entera truncaría el cociente a cero antes de que la multiplicación llegara a ocurrir; el punto decimal fuerza aritmética en coma flotante. Es de esos detalles que devuelven en silencio una columna de ceros.

La columna de margen queda entre el 58,5% y el 60,7% en todas las regiones — en Dataset y resultados está por qué esa horquilla es ruido y no un hallazgo.


2 — Los 5 comerciales con más ingreso

Devuelve 5 filas de 20 comerciales. El conjunto de datos solo lleva un identificador, no un nombre: no hay ninguna columna salesperson contra la que cruzar.

Para SQL Server, LIMIT 5 se escribe como SELECT TOP 5.


3 — Distribución de clientes por categoría de producto

Devuelve 9 filas — tres categorías × tres tipos de cliente. El ORDER BY sobre dos claves es lo que la hace legible: las categorías se mantienen agrupadas y, dentro de cada una, los tipos de cliente salen ordenados.


4 — Tendencia mensual de ventas

Devuelve 12 filas, una por mes de 2024. Es la consulta para alimentar un gráfico de líneas en Power BI o Tableau.

strftime es exclusiva de SQLite. En PostgreSQL, TO_CHAR(SaleDate, 'YYYY-MM'); en MySQL, DATE_FORMAT(SaleDate, '%Y-%m').

Como las fechas se sortean uniformemente a lo largo del año, los doce valores salen prácticamente planos. Una cartera real no se comportaría así.


5 — Categorías con beneficio medio bajo

Devuelve 0 filas. Las tres categorías promedian entre 1.470 y 1.543 de beneficio, así que ninguna baja del umbral. Es la consulta funcionando tal y como está escrita, no un fallo — y es la ilustración útil de qué hace HAVING: filtra después de la agregación y sobre el propio agregado, que es justo lo que un WHERE no puede hacer.