

 Amazon Redshift dejará de admitir la creación de nuevas UDF de Python a partir del parche 198. Las UDF de Python existentes seguirán funcionando hasta el 30 de junio de 2026. Para obtener más información, consulte la [publicación del blog](https://aws.amazon.com/blogs/big-data/amazon-redshift-python-user-defined-functions-will-reach-end-of-support-after-june-30-2026/). 

# Tutorial: Consulta de datos anidados con Amazon Redshift Spectrum
<a name="tutorial-query-nested-data"></a>

En este tutorial se muestra cómo consultar datos anidados con Redshift Spectrum. Los datos anidados son datos que contienen campos anidados. Los campos anidados son campos que se unen como una sola entidad, por ejemplo, matrices, estructuras u objetos. 

**Topics**
+ [Descripción general](#tutorial-nested-data-overview)
+ [Paso 1: Crear una tabla externa que contenga datos anidados](#tutorial-nested-data-create-table)
+ [Paso 2: Consultar los datos anidados en Amazon S3 con extensiones SQL](#tutorial-query-nested-data-sqlextensions)
+ [Casos de uso de datos anidados](nested-data-use-cases.md)
+ [Limitaciones de los datos anidados (versión preliminar)](nested-data-restrictions.md)
+ [Serialización de datos JSON anidados y complejos](serializing-complex-JSON.md)

## Descripción general
<a name="tutorial-nested-data-overview"></a>

Amazon Redshift Spectrum admite la consulta de datos anidados en los formatos de archivos Parquet, ORC, JSON e Ion. Redshift Spectrum obtiene acceso a los datos mediante el uso de tablas externas. Puede crear tablas externas que usen los tipos de datos complejos `struct`, `array` y `map`.

Supongamos, por ejemplo, que su archivo de datos contiene los siguientes datos en Amazon S3 en una carpeta llamada `customers`. Aunque no hay un solo elemento raíz, cada objeto JSON de estos datos de ejemplo representa una fila en una tabla. 

```
{"id": 1,
 "name": {"given": "John", "family": "Smith"},
 "phones": ["123-457789"],
 "orders": [{"shipdate": "2018-03-01T11:59:59.000Z", "price": 100.50},
            {"shipdate": "2018-03-01T09:10:00.000Z", "price": 99.12}]
}
{"id": 2,
 "name": {"given": "Jenny", "family": "Doe"},
 "phones": ["858-8675309", "415-9876543"],
 "orders": []
}
{"id": 3,
 "name": {"given": "Andy", "family": "Jones"},
 "phones": [],
 "orders": [{"shipdate": "2018-03-02T08:02:15.000Z", "price": 13.50}]
}
```

Puede usar Amazon Redshift Spectrum para consultar datos anidados en archivos. El siguiente tutorial le muestra cómo hacerlo con los datos de Apache Parquet.

### Requisitos previos
<a name="tutorial-nested-data-prereq"></a>

Si aún no usa Redshift Spectrum, siga los pasos en el tutorial de [Introducción a Amazon Redshift Spectrum](c-getting-started-using-spectrum.md) antes de continuar.

Para crear un esquema externo, reemplace el ARN del rol de IAM en el siguiente comando por el ARN del rol que creó en [Creación de un rol de IAM](c-getting-started-using-spectrum.md#c-getting-started-using-spectrum-create-role). Luego, ejecute el comando en cliente SQL.

```
create external schema spectrum 
from data catalog 
database 'myspectrum_db' 
iam_role 'arn:aws:iam::123456789012:role/myspectrum_role'
create external database if not exists;
```

## Paso 1: Crear una tabla externa que contenga datos anidados
<a name="tutorial-nested-data-create-table"></a>

Puede ver el [origen de datos](https://s3.amazonaws.com/redshift-downloads/tickit/spectrum/customers/customer_file1) descargándolo de Amazon S3. 

Para crear la tabla externa para este tutorial, ejecute el siguiente comando. 

```
CREATE EXTERNAL TABLE spectrum.customers (
  id     int,
  name   struct<given:varchar(20), family:varchar(20)>,
  phones array<varchar(20)>,
  orders array<struct<shipdate:timestamp, price:double precision>>
)
STORED AS PARQUET
LOCATION 's3://redshift-downloads/tickit/spectrum/customers/';
```

En el ejemplo anterior, la tabla externa `spectrum.customers` utiliza los tipos de datos `struct` y `array` para definir columnas con datos anidados. Amazon Redshift Spectrum admite la consulta de datos anidados en los formatos de archivos Parquet, ORC, JSON e Ion. El parámetro `STORED AS` es `PARQUET` para los archivos de Apache Parquet. El parámetro `LOCATION` tiene que hacer referencia a la carpeta de Amazon S3 que contiene los datos o los archivos anidados. Para obtener más información, consulte [CREATE EXTERNAL TABLE](r_CREATE_EXTERNAL_TABLE.md).

Puede anidar tipos `array` y `struct` en cualquier nivel. Por ejemplo, puede definir una columna denominada `toparray` tal como se muestra en el siguiente ejemplo.

```
toparray array<struct<nestedarray:
         array<struct<morenestedarray: 
         array<string>>>>>
```

También puede anidar los tipos `struct` tal como se muestra para la columna `x` en el siguiente ejemplo.

```
x struct<a: string,
         b: struct<c: integer,
                   d: struct<e: string>
                  >
        >
```

## Paso 2: Consultar los datos anidados en Amazon S3 con extensiones SQL
<a name="tutorial-query-nested-data-sqlextensions"></a>

Redshift Spectrum permite consultar los tipos complejos `array`, `map` y `struct` mediante extensiones de la sintaxis SQL de Amazon Redshift. 

### Extensión 1: Acceso a columnas de estructuras
<a name="nested-data-sqlextension1"></a>

Puede extraer datos de columnas de `struct` mediante una notación de puntos que concatene nombres de campos para crear rutas. Por ejemplo, la siguiente consulta devuelve los nombres y los apellidos de los clientes. El acceso al nombre se consigue con la ruta larga `c.name.given`. El acceso al apellido se consigue con la ruta larga `c.name.family`. 

```
SELECT c.id, c.name.given, c.name.family
FROM   spectrum.customers c;
```

La consulta anterior devuelve los siguientes datos.

```
id | given | family
---|-------|-------
1  | John  | Smith
2  | Jenny | Doe
3  | Andy  | Jones
(3 rows)
```

Una `struct` puede ser una columna de otra `struct`, que a su vez puede ser una columna de otra `struct`, en cualquier nivel. Las rutas que ofrecen acceso a columnas en `struct` profundamente anidadas pueden ser arbitrariamente largas. Por ejemplo, consulte la definición de la columna `x` a continuación.

```
x struct<a: string,
         b: struct<c: integer, 
                      d: struct<e: string>
                  >
        >
```

Puede obtener acceso a los datos en `e` como `x.b.d.e`.

### Extensión 2: Desplazamiento por matrices en una cláusula FROM
<a name="nested-data-sqlextension2"></a>

Puede extraer datos de columnas `array` (y, por extensión, de columnas `map`) especificando las columnas `array` en una cláusula `FROM` en lugar de nombres de tablas. La extensión se aplica a la cláusula `FROM` de la consulta principal y también a las cláusulas `FROM` de las subconsultas.

Puede hacer referencia a los elementos `array` por posición como, por ejemplo, `c.orders[0]`. (versión preliminar)

Mediante la combinación del desplazamiento por `arrays` con las uniones, se pueden conseguir varios tipos de aplanamientos, tal como se explica en los siguientes casos de uso. 

#### Aplanamiento mediante combinaciones interiores
<a name="unnest-inner-joins"></a>

La siguiente consulta selecciona los ID de cliente y las fechas de envío de los pedidos para los clientes que tienen pedidos. La extensión SQL en la cláusula FROM `c.orders o` depende del alias `c`.

```
SELECT c.id, o.shipdate
FROM   spectrum.customers c, c.orders o
```

Para cada cliente `c` que tiene pedidos, la cláusula `FROM` devuelve una fila para cada pedido `o` del cliente `c`. La fila combina la fila de cliente `c` y la fila de pedido `o`. A continuación, la cláusula `SELECT` solo conserva `c.id` y `o.shipdate`. El resultado es el siguiente.

```
id|      shipdate
--|----------------------
1 |2018-03-01  11:59:59
1 |2018-03-01  09:10:00
3 |2018-03-02  08:02:15
(3 rows)
```

El alias `c` proporciona acceso a los campos del cliente y el alias `o` proporciona acceso a los campos de los pedidos. 

Las semánticas son similares al SQL estándar. Puede considerar una cláusula `FROM` como si ejecutara el siguiente bucle anidado, seguido de `SELECT` para elegir los campos de la salida. 

```
for each customer c in spectrum.customers
  for each order o in c.orders
     output c.id and o.shipdate
```

Por consiguiente, si un cliente no tuviera un pedido, no aparecería en el resultado.

También puede considerar esto como la cláusula `FROM` que realiza una `JOIN` con la tabla `customers` y la matriz `orders`. De hecho, también puede escribir la consulta tal como se muestra en el siguiente ejemplo.

```
SELECT c.id, o.shipdate
FROM   spectrum.customers c INNER JOIN c.orders o ON true
```

**nota**  
Si existe un esquema denominado `c` con una tabla llamada `orders`, entonces `c.orders` hará referencia a la tabla `orders` y no a la columna matriz de `customers`.

#### Aplanamiento mediante combinaciones izquierdas
<a name="unnest-left-joins"></a>

La siguiente consulta devuelve todos los nombres de los clientes y sus pedidos. Si un cliente no ha realizado ningún pedido, también se devolverá el nombre del cliente. No obstante, en este caso, las columnas de pedido son NULL, tal y como se muestra en el siguiente ejemplo para Jenny Doe.

```
SELECT c.id, c.name.given, c.name.family, o.shipdate, o.price
FROM   spectrum.customers c LEFT JOIN c.orders o ON true
```

La consulta anterior devuelve los siguientes datos.

```
id  |  given  | family  |    shipdate          | price
----|---------|---------|----------------------|--------
 1  |  John   | Smith   | 2018-03-01  11:59:59 | 100.5
 1  |  John   | Smith   | 2018-03-01  09:10:00 |  99.12
 2  |  Jenny  | Doe     |                      |
 3  |  Andy   | Jones   | 2018-03-02  08:02:15 |  13.5
 (4 rows)
```

### Extensión 3: Acceso a una matriz de escalares directamente mediante un alias
<a name="nested-data-sqlextension3"></a>

Cuando un alias `p` en una cláusula `FROM` toma valores de una matriz de escalares, la consulta hace referencia a los valores de `p` como `p`. Por ejemplo, la siguiente consulta devuelve pares de nombres de clientes y números de teléfono.

```
SELECT c.name.given, c.name.family, p AS phone
FROM   spectrum.customers c LEFT JOIN c.phones p ON true
```

La consulta anterior devuelve los siguientes datos.

```
given  |  family  |  phone
-------|----------|-----------
John   | Smith    | 123-4577891
Jenny  | Doe      | 858-8675309
Jenny  | Doe      | 415-9876543
Andy   | Jones    | 
(4 rows)
```

### Extensión 4: Acceso a elementos de asignaciones
<a name="nested-data-sqlextension4"></a>

Redshift Spectrum trata el tipo de dato `map` como un tipo `array` que contiene tipos `struct` con una columna `key` y una columna `value`. La columna `key` debe ser `scalar`; el valor puede ser cualquier tipo de dato. 

Por ejemplo, el siguiente código crea una tabla externa con `map` para almacenar números de teléfono.

```
CREATE EXTERNAL TABLE spectrum.customers2 (
  id     int,
  name   struct<given:varchar(20), family:varchar(20)>,
  phones map<varchar(20), varchar(20)>,
  orders array<struct<shipdate:timestamp, price:double precision>>
)
STORED AS PARQUET
LOCATION 's3://redshift-downloads/tickit/spectrum/customers/';
```

Como un tipo `map` se comporta igual que un tipo `array` con columnas `key` y `value`, puede considerar los anteriores esquemas como si fueran el siguiente.

```
CREATE EXTERNAL TABLE spectrum.customers3 (
  id     int,
  name   struct<given:varchar(20), family:varchar(20)>,
  phones array<struct<key:varchar(20), value:varchar(20)>>,
  orders array<struct<shipdate:timestamp, price:double precision>>
)
STORED AS PARQUET
LOCATION 's3://redshift-downloads/tickit/spectrum/customers/';
```

La siguiente consulta devuelve los nombres de clientes con un número de teléfono móvil, y devuelve el número para cada nombre. La consulta de asignaciones se trata como si fuera el equivalente a consultar una `array` anidada de tipos `struct`. La siguiente consulta solo devolverá datos si creó la tabla externa tal y como se describió anteriormente. 

```
SELECT c.name.given, c.name.family, p.value 
FROM   spectrum.customers c, c.phones p 
WHERE  p.key = 'mobile';
```

**nota**  
La columna `key` para una `map` es una `string` para los tipos de archivo de Ion y JSON.