Skip to content

Commit 810a088

Browse files
Explain ambiguous ARRAY text and preserve the stack section anchor
1 parent dea235f commit 810a088

1 file changed

Lines changed: 10 additions & 7 deletions

File tree

‎docs/sqlalchemy.md‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,18 +1084,18 @@ CREATE TABLE orders (
10841084
)
10851085
```
10861086

1087-
#### Querying ARRAY data with typed SQLAlchemy expressions
1087+
#### Querying ARRAY data
10881088

10891089
Use `select()` with `ARRAY` or `AthenaArray` columns whose element types are known, either declared explicitly or reflected from Athena, to receive typed Python collections.
10901090
For example, the `events` table above returns `numbers` as a list of integers and `labels` as nested lists of strings.
1091-
SQLAlchemy serializes these result columns as JSON in Athena and converts the returned values according to the column types.
1091+
PyAthena projects these result columns as JSON in the generated SQL and converts the returned values according to the column types.
10921092
You do not need to call `json.loads()` on these results.
10931093
This preserves strings such as `"a,b"`, `"001"`, and `"null"` as strings, including within nested arrays.
10941094

10951095
#### Direct cursor and textual SQL results
10961096

10971097
Direct `cursor.execute()` calls and untyped SQLAlchemy `text()` queries use the cursor's existing conversion behavior.
1098-
The examples in this section use the standard REST cursor with its default converter and no result type hints or custom converters.
1098+
The examples in this section use a standard REST `cursor` created as in [Basic usage](usage.md#basic-usage), with its default converter and no result type hints or custom converters.
10991099
Other cursor implementations have their own conversion behavior.
11001100

11011101
The standard converter already converts simple ARRAY values to Python lists:
@@ -1114,19 +1114,22 @@ The following examples show its behavior for strings received as ARRAY values:
11141114
| ARRAY text | Python result |
11151115
|---|---|
11161116
| `[1, 2, 3]` | `[1, 2, 3]` (`list`) |
1117+
| `[one, two]` | `["one", "two"]` (`list`) |
11171118
| `[[1, 2], [3, 4]]` | `[[1, 2], [3, 4]]` (nested `list`) |
11181119
| `[[one, two], [three]]` | `"[[one, two], [three]]"` (`str`) |
11191120
| `[a, b=1]` | `"[a, b=1]"` (`str`) |
11201121

11211122
The numeric examples are valid JSON.
11221123
The unquoted nested string array is not valid JSON, and the native parser does not support nested arrays.
1123-
The last example contains an equals sign that the native parser rejects.
1124+
In the last example, `b=1` is outside a `{...}` ROW element, so the native parser rejects it.
11241125
For these unsupported representations, the converter returns the original string rather than dropping unparsed elements.
11251126
A string result therefore does not necessarily mean the stored ARRAY is invalid.
11261127
Calling `json.loads()` on that native text will not resolve these cases because it is not JSON.
11271128

1128-
Use typed SQLAlchemy SELECT expressions when element types and nested string values must be preserved.
1129-
When writing SQL directly, explicitly request JSON as shown below.
1129+
A list result alone does not guarantee that the original elements were preserved.
1130+
For example, the native text `[a,b, null]` becomes `["a", "b", None]`, which would be incorrect for an original array of two strings, `["a,b", "null"]`.
1131+
The native representation does not distinguish commas within strings from element separators, or the string `"null"` from a NULL element.
1132+
Use typed SQLAlchemy SELECT expressions for string elements or nested arrays, or explicitly request JSON when writing SQL directly, as shown below.
11301133

11311134
#### Requesting JSON in direct SQL
11321135

@@ -1166,7 +1169,7 @@ AthenaArray(AthenaArray(Integer)) # ARRAY<ARRAY<INT>>
11661169
#### Best practices
11671170

11681171
1. Declare the ARRAY element type and use typed SQLAlchemy SELECT expressions to preserve nested values and scalar types.
1169-
2. For direct cursor or untyped `text()` queries, request `CAST(... AS JSON)` when the native text parser cannot represent the result reliably.
1172+
2. For direct cursor or untyped `text()` queries, request `CAST(... AS JSON)` to preserve string elements and nested arrays.
11701173
3. Handle SQL NULL and empty arrays before accessing an element:
11711174

11721175
```python

0 commit comments

Comments
 (0)