Query EIA Dataframes
eia_dataframe_queryRun a single-statement SELECT against canvas dataframes registered by eia_query_route calls that passed stage: true — a query that staged nothing leaves no table to select from. Standard DuckDB SQL — joins, aggregates, window functions, CTEs all supported. Reference dataframes by the df_ handles returned by eia_query_route or listed by eia_dataframe_describe. Read-only: writes, DDL, DROP, COPY, PRAGMA, ATTACH, and external-file table functions are rejected. System catalogs (information_schema, pg_catalog, sqlite_master, duckdb_*) are denied. EIA data values are VARCHAR — use CAST(col AS DOUBLE) for arithmetic and aggregation. Optional register_as chains results as a new dataframe with a fresh expiry. Every dataframe named in the statement has its expiry extended by the query.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | Single-statement SELECT against df_<id> tables. EIA data columns are VARCHAR — use CAST(col AS DOUBLE) for arithmetic. Example: SELECT period, CAST(value AS DOUBLE) AS val FROM df_XXXXX ORDER BY period | |
| preview | No | Rows to include in the immediate response. Defaults to row_limit. Set lower when chaining via register_as and only a sample is needed inline. | |
| row_limit | No | Hard cap on rows materialized in the response (default 1000, max 10000). Rows past the cap are dropped without being counted — the response then carries truncated: true and a totalRows equal to the cap rather than a true total. Pass register_as to materialize the whole result instead and get an exact count. | |
| register_as | No | When set, persist the result as a new dataframe with a fresh expiry. Use to chain analyses without re-running upstream queries. The name must be unused — reusing a staged name is rejected, and the fix is a different name, not dropping the existing dataframe. eia_dataframe_describe lists the names already taken. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| rows | No | Materialized rows, bounded by preview / row_limit. | |
| error | No | Present when the call failed. Absent on success. | |
| notice | No | Guidance when either cap bound the response — names the cap that applied and how to reach the rows it withheld. | |
| columns | No | Column names in projection order. | |
| totalRows | No | Rows the query materialized. Exact when truncated is false — including on the register_as path, which stages and counts the whole result past row_limit. Equal to row_limit when truncated is true: a floor on the real match count, not a total. | |
| truncated | No | True when row_limit cut the result: more rows matched than the cap and the remainder was dropped without being counted. False when every matching row was materialized, including on the register_as path, which counts the new dataframe exactly. | |
| expires_at | No | ISO 8601 expiry for the newly registered dataframe, when applicable. Extended each time a later query references it. | |
| executedSql | No | Echo of the SQL statement that was executed — confirms the exact query that ran. | |
| returnedRows | No | Rows included in this response. | |
| registered_as | No | Set when register_as was supplied and the new dataframe was materialized. |