SQL + gobierno de datos
SQL + data governance

SQL Queries como Base de Limpieza, Control y Confianza en los Datos

SQL Queries as the Foundation for Data Cleaning, Control, and Trust

20 casos de uso prácticos para consultar, limpiar, validar, resumir y auditar datos directamente desde tablas. SQL no solo extrae data: también ayuda a descubrir errores, excepciones, duplicados y señales de negocio.

20 practical use cases for querying, cleaning, validating, summarizing, and auditing data directly from tables. SQL does not only extract data: it also helps uncover errors, exceptions, duplicates, and business signals.

¿Dónde encaja SQL en esta serie?

PowerShell ayuda a automatizar el entorno, Python integra y transforma datos, R analiza patrones estadísticos, pero SQL vive en el corazón de las bases de datos. Es el idioma natural para preguntar, filtrar, cruzar, resumir y auditar información donde realmente reside: en tablas relacionales.

SQL es especialmente valioso porque permite trabajar cerca de la fuente oficial. Antes de exportar a Excel, antes de cargar a Power BI y antes de crear un reporte ejecutivo, una buena consulta SQL puede detectar problemas de calidad, inconsistencias, duplicados, registros huérfanos y tendencias operativas.

Where does SQL fit in this series?

PowerShell helps automate the environment, Python integrates and transforms data, R analyzes statistical patterns, but SQL lives at the heart of databases. It is the natural language for asking, filtering, joining, summarizing, and auditing information where it truly resides: relational tables.

SQL is especially valuable because it works close to the official source. Before exporting to Excel, before loading Power BI, and before creating an executive report, a good SQL query can detect quality issues, inconsistencies, duplicates, orphan records, and operational trends.

ExploraciónExploration

1. Revisar los primeros registros de una tabla

1. Review the first records in a table

Sirve para entender rápidamente la estructura y los valores reales antes de diseñar una consulta más compleja.

Useful for quickly understanding structure and real values before designing a more complex query.

SELECT TOP 100
    *
FROM dbo.EmployeeMaster
ORDER BY Employee_ID;
CalidadQuality

2. Encontrar campos críticos vacíos

2. Find empty critical fields

Detecta registros incompletos que pueden romper reportes, cargas o validaciones.

Detect incomplete records that may break reports, loads, or validations.

SELECT
    Employee_ID,
    First_Name,
    Last_Name,
    Email,
    Department
FROM dbo.EmployeeMaster
WHERE Employee_ID IS NULL
   OR Email IS NULL
   OR Department IS NULL
   OR LTRIM(RTRIM(Email)) = '';
LimpiezaCleaning

3. Normalizar espacios en columnas de texto

3. Normalize spaces in text columns

Limpia espacios al inicio o final en nombres, departamentos o códigos administrativos.

Clean leading or trailing spaces in names, departments, or administrative codes.

SELECT
    Employee_ID,
    LTRIM(RTRIM(First_Name)) AS First_Name_Clean,
    LTRIM(RTRIM(Last_Name)) AS Last_Name_Clean,
    LTRIM(RTRIM(Department)) AS Department_Clean
FROM dbo.EmployeeMaster;
DuplicadosDuplicates

4. Detectar IDs duplicados

4. Detect duplicate IDs

Encuentra llaves que deberían ser únicas pero aparecen más de una vez.

Find keys that should be unique but appear more than once.

SELECT
    Employee_ID,
    COUNT(*) AS Record_Count
FROM dbo.EmployeeMaster
GROUP BY Employee_ID
HAVING COUNT(*) > 1;
Duplicados avanzadosAdvanced duplicates

5. Detectar posibles duplicados por nombre y fecha

5. Detect possible duplicates by name and date

No todos los duplicados tienen el mismo ID. Esta consulta busca personas que parecen repetidas.

Not all duplicates share the same ID. This query looks for people who appear repeated.

SELECT
    First_Name,
    Last_Name,
    Date_Of_Birth,
    COUNT(*) AS Possible_Duplicates
FROM dbo.EmployeeMaster
GROUP BY First_Name, Last_Name, Date_Of_Birth
HAVING COUNT(*) > 1;
AuditoríaAudit

6. Buscar empleados activos sin departamento

6. Find active employees without department

Ejemplo de regla de negocio: si alguien está activo, debería tener departamento asignado.

Example business rule: if someone is active, they should have an assigned department.

SELECT
    Employee_ID,
    Full_Name,
    Status,
    Department
FROM dbo.EmployeeMaster
WHERE Status = 'Active'
  AND (Department IS NULL OR LTRIM(RTRIM(Department)) = '');
CruceJoining

7. Cruzar empleados con departamentos

7. Join employees with departments

Trae información descriptiva desde una tabla maestra relacionada.

Bring descriptive information from a related master table.

SELECT
    e.Employee_ID,
    e.Full_Name,
    e.Department_ID,
    d.Department_Name,
    d.Division
FROM dbo.EmployeeMaster e
LEFT JOIN dbo.DepartmentMaster d
    ON e.Department_ID = d.Department_ID;
Registros huérfanosOrphan records

8. Encontrar registros sin match en la tabla maestra

8. Find records without a match in the master table

Detecta códigos o IDs que existen en una tabla transaccional pero no en la tabla oficial.

Detect codes or IDs that exist in a transaction table but not in the official master table.

SELECT
    t.Transaction_ID,
    t.Employee_ID,
    t.Transaction_Date
FROM dbo.TimeTransactions t
LEFT JOIN dbo.EmployeeMaster e
    ON t.Employee_ID = e.Employee_ID
WHERE e.Employee_ID IS NULL;
ResumenSummary

9. Contar registros por departamento

9. Count records by department

Una consulta simple para validar volúmenes antes de entregar un reporte.

A simple query to validate volumes before delivering a report.

SELECT
    Department,
    COUNT(*) AS Total_Employees
FROM dbo.EmployeeMaster
GROUP BY Department
ORDER BY Total_Employees DESC;
FechasDates

10. Agrupar transacciones por mes

10. Group transactions by month

Convierte eventos diarios en una tendencia mensual para análisis operativo.

Turn daily events into a monthly trend for operational analysis.

SELECT
    DATEFROMPARTS(YEAR(Transaction_Date), MONTH(Transaction_Date), 1) AS Month_Start,
    COUNT(*) AS Transaction_Count,
    SUM(Amount) AS Total_Amount
FROM dbo.Transactions
GROUP BY
    YEAR(Transaction_Date),
    MONTH(Transaction_Date)
ORDER BY Month_Start;
RankingRanking

11. Crear ranking por monto total

11. Create a ranking by total amount

Identifica los departamentos, programas o cuentas con mayor volumen.

Identify departments, programs, or accounts with the highest volume.

SELECT
    Department,
    SUM(Amount) AS Total_Amount,
    RANK() OVER (ORDER BY SUM(Amount) DESC) AS Amount_Rank
FROM dbo.Transactions
GROUP BY Department;
VentanasWindow functions

12. Comparar cada registro contra el promedio de su grupo

12. Compare each record against its group average

Permite detectar registros por encima o por debajo del comportamiento normal de su propio grupo.

Detect records above or below the normal behavior of their own group.

SELECT
    Employee_ID,
    Department,
    Amount,
    AVG(Amount) OVER (PARTITION BY Department) AS Dept_Avg_Amount,
    Amount - AVG(Amount) OVER (PARTITION BY Department) AS Difference_From_Avg
FROM dbo.Transactions;
Último registroLatest record

13. Obtener el registro más reciente por empleado

13. Get the latest record by employee

Muy útil para estados actuales, última transacción, último pago o última actualización.

Very useful for current status, latest transaction, latest payment, or latest update.

WITH ranked AS (
    SELECT
        Employee_ID,
        Status,
        Effective_Date,
        ROW_NUMBER() OVER (
            PARTITION BY Employee_ID
            ORDER BY Effective_Date DESC
        ) AS rn
    FROM dbo.EmployeeStatusHistory
)
SELECT *
FROM ranked
WHERE rn = 1;
ValidaciónValidation

14. Validar códigos permitidos

14. Validate allowed codes

Detecta registros que usan códigos fuera de una lista oficial de valores válidos.

Detect records using codes outside an official list of valid values.

SELECT
    Employee_ID,
    Status_Code
FROM dbo.EmployeeMaster
WHERE Status_Code NOT IN ('A', 'I', 'L', 'T');
CASECASE

15. Crear categorías con lógica de negocio

15. Create categories with business logic

Convierte valores numéricos o textuales en grupos fáciles de analizar.

Convert numeric or text values into groups that are easier to analyze.

SELECT
    Employee_ID,
    Amount,
    CASE
        WHEN Amount < 100 THEN 'Low'
        WHEN Amount BETWEEN 100 AND 999 THEN 'Medium'
        WHEN Amount >= 1000 THEN 'High'
        ELSE 'Unknown'
    END AS Amount_Category
FROM dbo.Transactions;
ExcepcionesExceptions

16. Detectar transacciones fuera de horario

16. Detect transactions outside business hours

Ejemplo de auditoría para operaciones registradas en horarios poco comunes.

Audit example for operations recorded at unusual times.

SELECT
    Transaction_ID,
    Employee_ID,
    Transaction_DateTime
FROM dbo.Transactions
WHERE DATEPART(HOUR, Transaction_DateTime) < 7
   OR DATEPART(HOUR, Transaction_DateTime) >= 19;
TendenciasTrends

17. Comparar mes actual contra mes anterior

17. Compare current month against previous month

Permite ver crecimiento, caída o cambios operativos mes a mes.

Shows growth, decline, or operational changes month over month.

WITH monthly AS (
    SELECT
        DATEFROMPARTS(YEAR(Transaction_Date), MONTH(Transaction_Date), 1) AS Month_Start,
        SUM(Amount) AS Total_Amount
    FROM dbo.Transactions
    GROUP BY YEAR(Transaction_Date), MONTH(Transaction_Date)
)
SELECT
    Month_Start,
    Total_Amount,
    LAG(Total_Amount) OVER (ORDER BY Month_Start) AS Previous_Month_Amount,
    Total_Amount - LAG(Total_Amount) OVER (ORDER BY Month_Start) AS Month_Change
FROM monthly;
Preparación BIBI preparation

18. Crear una vista limpia para Power BI

18. Create a clean view for Power BI

Centraliza reglas de limpieza para que el dashboard consuma una fuente más confiable.

Centralize cleaning rules so the dashboard consumes a more reliable source.

CREATE VIEW reporting.vw_Employee_Clean AS
SELECT
    Employee_ID,
    LTRIM(RTRIM(Full_Name)) AS Full_Name,
    UPPER(LTRIM(RTRIM(Status_Code))) AS Status_Code,
    Department_ID,
    CAST(Hire_Date AS date) AS Hire_Date
FROM dbo.EmployeeMaster
WHERE Employee_ID IS NOT NULL;
StagingStaging

19. Insertar data limpia en una tabla staging

19. Insert clean data into a staging table

Prepara datos antes de cargarlos a una tabla final o proceso ETL.

Prepare data before loading it into a final table or ETL process.

INSERT INTO staging.EmployeeClean (
    Employee_ID,
    Full_Name,
    Email,
    Department
)
SELECT
    Employee_ID,
    LTRIM(RTRIM(Full_Name)),
    LOWER(LTRIM(RTRIM(Email))),
    LTRIM(RTRIM(Department))
FROM staging.EmployeeRaw
WHERE Employee_ID IS NOT NULL
  AND Email LIKE '%@%';
Auditoría finalFinal audit

20. Crear un reporte de calidad de datos

20. Create a data quality report

Resume problemas principales en una sola salida para revisión técnica o gerencial.

Summarize the main issues in one output for technical or management review.

SELECT
    'Missing Email' AS Issue_Type,
    COUNT(*) AS Issue_Count
FROM dbo.EmployeeMaster
WHERE Email IS NULL OR LTRIM(RTRIM(Email)) = ''

UNION ALL

SELECT
    'Missing Department' AS Issue_Type,
    COUNT(*) AS Issue_Count
FROM dbo.EmployeeMaster
WHERE Department IS NULL OR LTRIM(RTRIM(Department)) = ''

UNION ALL

SELECT
    'Duplicate Employee ID' AS Issue_Type,
    COUNT(*) AS Issue_Count
FROM (
    SELECT Employee_ID
    FROM dbo.EmployeeMaster
    GROUP BY Employee_ID
    HAVING COUNT(*) > 1
) d;