# Escritura de consultas SQL

Dashboard Studio utiliza SQL para recuperar datos de los esquemas de IoT Query. Usted escribe SQL en dos contextos: editores de paneles, donde las sentencias impulsan visualizaciones, y el SQL Editor independiente para la exploración de datos. Esta página explica cómo escribir SQL eficaz para ambos contextos, con énfasis en los requisitos de visualización, ya que tienen restricciones estructurales específicas.

### Dónde se utiliza SQL

Dashboard Studio proporciona dos entornos SQL para diferentes propósitos. Comprender cuándo usar cada uno le ayuda a trabajar de manera más eficiente.

[**Consultas de visualización**](#how-to-write-sql-for-visualizations) impulsan paneles individuales en informes. Usted escribe estas sentencias en la pestaña **Consulta SQL** tab. Cada panel ejecuta una sentencia que debe devolver datos en una estructura específica que coincida con el tipo de visualización. Estas sentencias se ejecutan cuando los informes se cargan o se actualizan, por lo que el rendimiento importa para la experiencia del usuario. El SQL de visualización no puede modificar datos; todas las sentencias se ejecutan como operaciones SELECT de solo lectura en los esquemas de IoT Query.

**Informes** utilizan el mismo enfoque de SQL de visualización que los paneles del dashboard. Un informe ejecuta una consulta que impulsa tres vistas simultáneamente: la tabla de datos, el gráfico y el mapa de ubicación. La sentencia debe devolver todas las columnas necesarias en los tres componentes, así que incluya columnas de coordenadas, tiempo y métricas juntas en un único SELECT.

[**SQL Editor**](#how-to-use-the-sql-editor) admite exploración y exportación de datos. Acceda al SQL Editor desde la barra lateral izquierda en Tools. Escriba cualquier sentencia SELECT para examinar la estructura de los datos, validar supuestos o exportar resultados como CSV. El SQL Editor muestra tablas de resultados completas con ordenación de columnas y proporciona métricas de ejecución. Úselo para probar lógica antes de agregar SQL a los paneles de visualización, o para extracción ad hoc de datos que no necesita visualización.

{% hint style="info" %}
**La diferencia clave**: el SQL de visualización debe coincidir con estructuras exactas de columnas, mientras que las sentencias del SQL Editor pueden devolver cualquier formato de resultado. Pruebe primero la lógica compleja en SQL Editor y luego adáptela para las visualizaciones.
{% endhint %}

### Cómo escribir SQL para visualizaciones

<figure><img src="/files/7da9cf54f18a39d4e53b6299bf6e7cdea2c82ba4" alt=""><figcaption></figcaption></figure>

El SQL de visualización debe devolver cantidades específicas de columnas y tipos de datos. Dashboard Studio no puede renderizar un gráfico de barras a partir de tres columnas ni un mosaico de estadísticas a partir de datos de texto. Revise la sección Dataset Requirements en la pestaña SQL Query para ver exactamente qué espera la visualización elegida antes de escribir la sentencia. La tabla siguiente contiene los tipos de visualización admitidos:

| Visualización                          | Requisito de consulta          | Ejemplo                                                           |
| -------------------------------------- | ------------------------------ | ----------------------------------------------------------------- |
| [Mosaico de estadísticas](#stat-tiles) | Un solo valor numérico         | `SELECT COUNT(*) FROM schema.table`                               |
| [Gráfico de barras](#bar-charts)       | Dos columnas: categoría, valor | `SELECT column1, COUNT(*) FROM schema.table GROUP BY column1`     |
| [Gráfico circular](#pie-charts)        | Dos columnas: etiqueta, valor  | `SELECT category, SUM(value) FROM schema.table GROUP BY category` |
| [Tabla](#tables)                       | Cualquier columna              | `SELECT column1, column2, column3 FROM schema.table`              |
| [Texto](#text-panels)                  | No se requiere consulta        | Solo contenido Markdown                                           |

<details>

<summary>Tarjetas de estadística</summary>

Los mosaicos de estadísticas muestran valores numéricos únicos. Las sentencias deben devolver exactamente una fila con una columna numérica:

{% code title="Total de viajes en el mes actual" overflow="wrap" %}

```sql
SELECT COUNT(*) as value
FROM silver.trips
WHERE start_time >= DATE_TRUNC('month', CURRENT_DATE);
```

{% endcode %}

{% code title="Distancia total recorrida (km)" overflow="wrap" %}

```sql
SELECT SUM(distance_km) as value
FROM silver.trips
WHERE start_time >= CURRENT_DATE - INTERVAL '7 days';
```

{% endcode %}

El nombre de la columna no importa, solo que el resultado sea un único valor numérico. Dashboard Studio muestra este valor con el formato que usted configura en Visualization Settings.

</details>

<details>

<summary>Gráficos de barras</summary>

Los gráficos de barras requieren exactamente dos columnas: categoría (texto o fecha) y valor (numérico). La primera columna se convierte en el eje X, la segunda se convierte en la altura de las barras:

{% code title="Viajes por tipo de vehículo" overflow="wrap" %}

```sql
SELECT 
  vehicle_type as category,
  COUNT(*) as value
FROM silver.trips
WHERE start_time >= DATE_TRUNC('month', CURRENT_DATE)
GROUP BY vehicle_type
ORDER BY value DESC;
```

{% endcode %}

{% code title="Conteos diarios de viajes" overflow="wrap" %}

```sql
SELECT 
  DATE_TRUNC('day', start_time)::date as category,
  COUNT(*) as value
FROM silver.trips
WHERE start_time >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY DATE_TRUNC('day', start_time)
ORDER BY category;
```

{% endcode %}

Use `ORDER BY` para controlar la secuencia de las barras. Ordene por valor para comparaciones clasificadas o por categoría para progresiones de series temporales.

</details>

<details>

<summary>Gráficos circulares</summary>

Los gráficos circulares requieren exactamente dos columnas: etiqueta (texto) y valor (numérico). La primera columna se convierte en las etiquetas de las porciones, la segunda determina el tamaño de las porciones:

{% code title="Distribución de viajes por zona" %}

```sql
SELECT 
  zone_name as label,
  COUNT(*) as value
FROM silver.zone_visits
WHERE enter_time >= DATE_TRUNC('month', CURRENT_DATE)
GROUP BY zone_name
ORDER BY value DESC
LIMIT 10;
```

{% endcode %}

Agregue cláusulas LIMIT para categorías con muchos valores. Los gráficos circulares con más de 20 porciones se vuelven ilegibles; limítelos a las 10-15 categorías principales.

</details>

<details>

<summary>Tablas</summary>

Las tablas aceptan cualquier cantidad de columnas con cualquier tipo de datos. Seleccione las columnas que desea mostrar:

{% code title="Detalles de viajes recientes" %}

```sql
SELECT 
  device_id,
  start_time,
  end_time,
  distance_km,
  duration_minutes,
  max_speed_kmh
FROM silver.trips
WHERE start_time >= CURRENT_DATE - INTERVAL '7 days'
ORDER BY start_time DESC
LIMIT 100;
```

{% endcode %}

Los nombres de las columnas se convierten en encabezados de tabla. Use alias con espacios para encabezados legibles: `distance_km as "Distance (km)"`.

</details>

<details>

<summary>Paneles de texto</summary>

Los paneles de texto muestran valores de texto únicos o cadenas con formato. Las sentencias deben devolver una columna de texto:

{% code title="Marca de tiempo de la última actualización de datos" %}

```sql
SELECT 
  'Last updated: ' || MAX(record_added_at)::text as value
FROM bronze.tracking_data_core;
```

{% endcode %}

</details>

Las consultas de informes siguen las mismas reglas estructurales que las consultas de visualización en paneles de dashboard. Debido a que una sola sentencia impulsa la tabla de datos, el gráfico y el mapa de ubicación en conjunto, es posible que necesite combinar columnas que se escribirían como consultas de paneles separadas en un dashboard. Por ejemplo, una consulta de panel de gráfico de barras que devuelve dos columnas no es suficiente para un informe que también necesita coordenadas GPS para el mapa de ubicación. Incluya todas las columnas requeridas para cada componente en una sola sentencia. La lógica principal de filtrado y JOIN sigue siendo la misma que en las consultas de paneles; solo la cláusula SELECT necesita ser más amplia.

### Cómo escribir SQL para informes

Un informe ejecuta una consulta SQL que impulsa tres componentes simultáneamente: la tabla de datos, el gráfico y el mapa de ubicación. A diferencia de los paneles del dashboard, donde cada panel tiene su propia consulta específica, una consulta de informe debe devolver todas las columnas necesarias en cada componente en una sola sentencia SELECT.

#### Requisitos de columnas por componente

Cada componente del informe tiene requisitos específicos de columnas. Su consulta debe satisfacer todos los componentes que haya habilitado.

| Componente        | Columnas requeridas                                                       | Notas                                                                   |
| ----------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| Tabla de datos    | Cualquier columna                                                         | Todas las columnas devueltas aparecen como columnas de tabla            |
| Gráfico           | Al menos una columna de tiempo o categoría, al menos una columna numérica | Las columnas de los ejes se seleccionan en la configuración del gráfico |
| Mapa de ubicación | Latitud y longitud como grados decimales                                  | Dashboard Studio detecta automáticamente las columnas de coordenadas    |

Como la tabla de datos acepta cualquier columna, no impone restricciones adicionales. El gráfico y el mapa de ubicación determinan la mayoría de las decisiones estructurales.

#### Combinación de componentes en una consulta

Una consulta que devuelve solo las columnas necesarias para un gráfico (dos columnas: categoría y valor) no también puede impulsar un mapa de ubicación. Debe incluir todas las columnas requeridas juntas.

El siguiente ejemplo devuelve columnas para los tres componentes: una columna de tiempo y una columna numérica para el gráfico, columnas de coordenadas para el mapa de ubicación y atributos adicionales que aparecen en la tabla de datos.

```sql
SELECT
    t.device_id,
    o.object_label,
    t.device_time,
    t.latitude::float / 10000000 AS latitude,
    t.longitude::float / 10000000 AS longitude,
    t.speed::float / 100 AS speed
FROM raw_telematics_data.tracking_data_core t
JOIN raw_business_data.objects o ON t.device_id = o.device_id
WHERE t.device_time >= NOW() - INTERVAL '24 hours'
ORDER BY t.device_time DESC
LIMIT 1000
```

En esta consulta, `device_time` y `speed` sirven al gráfico, `latitude` y `longitude` sirven al mapa de ubicación, y todas las columnas aparecen en la tabla de datos.

{% hint style="info" %}
Las tablas de telemática sin procesar almacenan coordenadas y velocidad como enteros escalados. Las coordenadas se dividen por 10,000,000 (10⁷) para convertirlas a grados decimales, y la velocidad se divide por 100 (10²) para convertirla a km/h. Aplique estas conversiones en cualquier consulta que lea de las tablas `raw_telematics_data` .
{% endhint %}

#### Adaptación de consultas de paneles de dashboard para informes

Cualquier consulta de panel de un dashboard es un punto de partida válido para un informe. El ajuste necesario depende de qué componentes desea habilitar.

Si la consulta del panel ya es una visualización de tabla que devuelve varias columnas, puede que ya incluya todo lo necesario. Agregue columnas de coordenadas si se requiere el mapa de ubicación.

Si la consulta del panel es una consulta de gráfico de barras o mosaico de estadísticas que devuelve resultados agregados, probablemente carece del detalle a nivel de fila necesario para la tabla de datos y el mapa de ubicación. En ese caso, elimine la agregación y trabaje a partir de los datos subyacentes sin procesar o de la capa Silver.

[SQL Recipe Book](/docs/analytics/es/example-queries.md) contiene ejemplos de consultas listos para usar para análisis comunes de flotas. Las recetas del libro pueden adaptarse para informes agregando columnas de coordenadas donde se necesite el mapa de ubicación. La lógica principal de WHERE y JOIN se transfiere directamente; ajuste solo la cláusula SELECT para cubrir todos los componentes requeridos.

### Cómo usar variables globales

Las variables globales proporcionan valores reutilizables en múltiples sentencias SQL. Defina variables en **Settings > Configuration > Global Variables**, y luego consúltelas usando la sintaxis `${variable_name}` .

<figure><img src="/files/261d9dcd6d9fd9d2d6a0ca6c1d7009ad537e6f33" alt=""><figcaption></figcaption></figure>

Defina variables para valores que cambian periódicamente pero permanecen consistentes en varios paneles: rangos de fechas de análisis, filtros de tipo de vehículo o valores umbral. Cuando estos valores cambien, actualice la definición de la variable una sola vez en lugar de editar sentencias SQL individuales.

{% code title="Uso de variables de rango de fechas" %}

```sql
SELECT 
  DATE_TRUNC('day', start_time)::date as category,
  COUNT(*) as value
FROM silver.trips
WHERE start_time >= '${analysis_start_date}'::date
  AND start_time < '${analysis_end_date}'::date
GROUP BY DATE_TRUNC('day', start_time)
ORDER BY category;
```

{% endcode %}

Las variables almacenan valores de texto. Conviértalas al tipo adecuado en SQL: `'${variable_name}'::date` para fechas, `'${variable_name}'::integer` para números.

Para parámetros específicos de la sentencia que cambian con frecuencia, puede usar bloques de parámetros CTE al inicio:

```sql
WITH params AS (
  SELECT 
    5 as min_idle_minutes,
    10 as max_idle_speed_kmh,
    '${analysis_start_date}'::date as date_from,
    '${analysis_end_date}'::date as date_to
)

SELECT 
  device_id,
  COUNT(*) as idle_count,
  SUM(duration_minutes) as total_idle_minutes
FROM silver.idle_events e
CROSS JOIN params p
WHERE e.event_time >= p.date_from
  AND e.event_time < p.date_to
  AND e.speed_kmh <= p.max_idle_speed_kmh
  AND e.duration_minutes >= p.min_idle_minutes
GROUP BY device_id
ORDER BY total_idle_minutes DESC;
```

Este patrón combina variables globales (rangos de fechas) con parámetros específicos de la sentencia (umbrales), manteniendo todos los valores ajustables en la parte superior para facilitar el mantenimiento.

### Cómo acceder a los esquemas de IoT Query

IoT Query organiza los datos en capas de Raw data, Transformation e Insight. Comprender qué capa usar ahorra tiempo y mejora la claridad del SQL. Para obtener detalles completos del esquema, consulte [IoT Query Schema Overview](https://www.navixy.com/docs/analytics/iotquery/schema-overview).

**Capa de datos sin procesar** contiene puntos de seguimiento sin procesar de los dispositivos: `bronze.tracking_data_core` almacena cada posición GPS con marcas de tiempo, coordenadas y lecturas de sensores. Use Raw data para análisis a nivel de punto o cuando necesite valores de sensores sin procesar que no se hayan procesado en capas superiores.

**Capa de transformación** proporciona entidades procesadas: `silver.trips` agrega puntos de seguimiento en registros de viajes con horas de inicio/fin, distancia y duración. `silver.zone_visits` registra cuándo los dispositivos entran y salen de geocercas. `silver.idle_events` identifica períodos en los que los vehículos permanecen estacionarios con los motores encendidos. Use Transformation para la mayoría de las necesidades de visualización, ya que proporciona estructuras listas para el análisis.

**Capa Insight** ofrece métricas preagregadas y modelos dimensionales para análisis complejos. Use Insight para estadísticas de toda la flota o análisis multidimensionales que requerirían joins complejos con tablas Silver.

Haga referencia a las tablas usando el formato `schema.table` : `silver.trips`, no solo `trips`. Incluya filtros de rango de fechas en las cláusulas WHERE para limitar los datos escaneados:

{% code title="Filtre siempre por rangos de tiempo" %}

```sql
SELECT device_id, COUNT(*) as trip_count
FROM silver.trips
WHERE start_time >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY device_id;
```

{% endcode %}

La mayoría de las sentencias SQL filtran por dispositivo, rango de tiempo o ambos. Agregue estos filtros al principio de las cláusulas WHERE para reducir el volumen de datos procesados.

### Cómo usar el SQL Editor

Acceda al SQL Editor desde la barra lateral izquierda en Tools. Úselo para tres propósitos principales: probar lógica antes de agregarla a los paneles, explorar esquemas de datos para comprender las columnas disponibles y exportar datos que no necesitan visualización.

<figure><img src="/files/6d2c5ff17fe01c2f6f09df6af26ee3e80515c182" alt=""><figcaption></figcaption></figure>

El SQL Editor admite múltiples pestañas para diferentes sentencias. Escriba SQL en las pestañas, ejecútelo con el botón "Execute Query" y vea los resultados en la tabla de abajo. Los resultados muestran métricas de ejecución (tiempo de ejecución, filas devueltas) y admiten ordenación de columnas para un examen rápido de los datos.

Exporte los resultados como CSV usando el botón "Export CSV". Esto funciona para informes ad hoc o extracciones de datos para análisis externos. El SQL Editor no tiene límite de filas de resultados, a diferencia del SQL de visualización que debería devolver conjuntos de datos específicos.

Pruebe el SQL de visualización en el SQL Editor antes de agregarlo a los paneles. Escriba la sentencia, verifique que devuelva las columnas y tipos de datos esperados, luego cópiela a la pestaña SQL Query del editor de paneles. Este flujo de trabajo detecta problemas estructurales antes de que configure los ajustes de visualización.

Patrón de exploración para datos nuevos:

{% code expandable="true" %}

```sql
-- 1. Examinar la estructura de la tabla
SELECT * FROM silver.trips LIMIT 10;

-- 2. Verificar la cobertura del rango de fechas
SELECT 
  MIN(start_time) as earliest,
  MAX(start_time) as latest,
  COUNT(*) as total_trips
FROM silver.trips;

-- 3. Probar la lógica de filtrado
SELECT 
  device_id,
  start_time,
  distance_km
FROM silver.trips
WHERE start_time >= '2024-01-01'
  AND device_id = 12345
ORDER BY start_time;

-- 4. Adaptar para visualización (2 columnas para gráfico de barras)
SELECT 
  DATE_TRUNC('day', start_time)::date as day,
  COUNT(*) as trips
FROM silver.trips
WHERE start_time >= '2024-01-01'
  AND device_id = 12345
GROUP BY DATE_TRUNC('day', start_time)
ORDER BY day;
```

{% endcode %}

### Patrones SQL comunes

La mayoría del SQL de visualización sigue patrones similares. Copie estas estructuras y ajuste filtros, columnas y agregaciones para sus necesidades específicas.

<details>

<summary><strong>Conteos de series temporales</strong> para seguir tendencias</summary>

```sql
SELECT 
  DATE_TRUNC('hour', start_time) as time_bucket,
  COUNT(*) as event_count
FROM silver.trips
WHERE start_time >= CURRENT_DATE - INTERVAL '24 hours'
GROUP BY DATE_TRUNC('hour', start_time)
ORDER BY time_bucket;
```

</details>

<details>

<summary><strong>Clasificaciones por categoría</strong> para comparar grupos</summary>

```sql
SELECT 
  category_column,
  COUNT(*) as count
FROM schema.table
WHERE filter_conditions
GROUP BY category_column
ORDER BY count DESC
LIMIT 15;
```

</details>

<details>

<summary><strong>Cálculos de métricas</strong> para estadísticas agregadas</summary>

```sql
SELECT 
  SUM(distance_km) as total_distance,
  AVG(duration_minutes) as avg_duration,
  COUNT(*) as trip_count
FROM silver.trips
WHERE start_time >= DATE_TRUNC('week', CURRENT_DATE);
```

</details>

<details>

<summary><strong>Resumenes filtrados</strong> con múltiples condiciones</summary>

```sql
SELECT 
  device_id,
  COUNT(*) as trips,
  SUM(distance_km) as total_km
FROM silver.trips
WHERE start_time >= '${period_start}'::date
  AND start_time < '${period_end}'::date
  AND distance_km >= 5
  AND duration_minutes >= 10
GROUP BY device_id
HAVING COUNT(*) >= 5
ORDER BY total_km DESC;
```

</details>

### Qué hacer cuando SQL falla

Los fallos de ejecución se dividen en tres categorías: incompatibilidades estructurales con los requisitos de visualización, errores de sintaxis SQL o filtros que no devuelven datos.

#### **Incompatibilidades en la estructura de columnas**

Ocurren cuando los resultados no coinciden con las expectativas de la visualización. Si seleccionó un gráfico de barras pero su SQL devuelve tres columnas, Dashboard Studio no puede renderizarlo. Revise Dataset Requirements en la pestaña SQL Query. El gráfico de barras necesita exactamente dos columnas (categoría, valor), así que ajuste su cláusula SELECT:

```sql
-- Incorrecto: tres columnas
SELECT device_id, start_time, COUNT(*) FROM silver.trips GROUP BY device_id, start_time;

-- Correcto: dos columnas
SELECT device_id, COUNT(*) as trips FROM silver.trips GROUP BY device_id;
```

#### **Errores de sintaxis SQL**

Muestran mensajes de error específicos. Los problemas comunes incluyen prefijos de esquema faltantes (`trips` en lugar de `silver.trips`), errores tipográficos en nombres de columnas o conversión incorrecta de fechas. Pruebe las sentencias en SQL Editor para ver mensajes de error detallados con números de línea.

#### **Resultados vacíos**

A pesar de una ejecución correcta, indican que los filtros excluyen todos los datos. Pruebe el SQL sin cláusulas WHERE en SQL Editor para verificar que la tabla contiene datos y luego agregue filtros de manera incremental para identificar qué condición excluye los resultados esperados.

#### Problemas de rendimiento

Si las sentencias se ejecutan lentamente o agotan el tiempo de espera, agregue filtros de rango de fechas a las cláusulas WHERE. Las operaciones que escanean tablas completas procesan millones de filas innecesariamente:

```sql
-- Lento: sin filtro de fecha
SELECT device_id, COUNT(*) FROM silver.trips GROUP BY device_id;

-- Rápido: filtro de rango de fechas
SELECT device_id, COUNT(*) 
FROM silver.trips 
WHERE start_time >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY device_id;
```

Para obtener orientación adicional sobre rendimiento, consulte [Cómo acceder a los esquemas de IoT Query](#how-to-access-iot-query-schemas) para conocer las mejores prácticas sobre filtrado y selección de esquemas.

### Dónde encontrar ejemplos de SQL

El [SQL Recipe Book](/docs/analytics/es/example-queries.md) proporciona ejemplos completos para análisis telemáticos comunes. Estas recetas demuestran patrones para análisis de viajes, cálculos de visitas a zonas, detección de ralentí y métricas de flota. Cada receta incluye la sentencia SQL completa, explicación de la lógica y resultados de muestra.

Adapte ejemplos de Recipe Book para visualizaciones ajustando la cláusula SELECT para que coincida con los requisitos de visualización. Una receta que devuelve registros detallados de viajes puede convertirse en un gráfico de barras agregando GROUP BY y agregación COUNT. Una sentencia que calcula métricas por vehículo puede convertirse en un mosaico de estadísticas agregando SUM en todos los vehículos.

Solo necesita:

1. Copiar ejemplos de [Recipe Book](/docs/analytics/es/example-queries.md) al Editor de Dashboard Studio.
2. Probar con sus datos reales.
3. Verificar los resultados y luego modificar la cláusula SELECT para su visualización de destino.

La lógica principal de WHERE y JOIN sigue siendo la misma; usted ajusta solo la estructura de salida.

Para obtener detalles del esquema, consulte [IoT Query Schema Overview](https://www.navixy.com/docs/analytics/iotquery/schema-overview). Esta referencia explica las tablas disponibles, las definiciones de columnas y las relaciones entre las capas Raw data, Transformation e Insight.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://navixy.com/docs/analytics/es/dashboard-studio/writing-sql-queries.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
