Execute a SQL query. By default, this uses duckdb to execute the query. Any dataframes in the global namespace can be used inside the query. You can also pass a custom engine to execute queries against other databases. The custom engine can be a DB-API 2.0 compatible connectio
(
query: str,
*,
output: bool = True,
engine: DBAPIConnection | None = None,
)
| 78 | |
| 79 | @mddoc |
| 80 | def sql( |
| 81 | query: str, |
| 82 | *, |
| 83 | output: bool = True, |
| 84 | engine: DBAPIConnection | None = None, |
| 85 | ) -> Any: |
| 86 | """ |
| 87 | Execute a SQL query. |
| 88 | |
| 89 | By default, this uses duckdb to execute the query. Any dataframes in the global |
| 90 | namespace can be used inside the query. |
| 91 | |
| 92 | You can also pass a custom engine to execute queries against other databases. |
| 93 | The custom engine can be a DB-API 2.0 compatible connection (PEP 249), including |
| 94 | DB-API wrappers provided by ADBC drivers. |
| 95 | |
| 96 | The result of the query is displayed in the UI if output is True. |
| 97 | |
| 98 | Args: |
| 99 | query: The SQL query to execute. |
| 100 | output: Whether to display the result in the UI. Defaults to True. |
| 101 | engine: Optional SQL engine to use. Can be a SQLAlchemy, DuckDB, Clickhouse, |
| 102 | Redshift, Ibis, or DB-API 2.0 compatible connection (including ADBC drivers). |
| 103 | If None, uses DuckDB. |
| 104 | |
| 105 | Returns: |
| 106 | The result of the query. |
| 107 | """ |
| 108 | if query is None or query.strip() == "": |
| 109 | return None |
| 110 | |
| 111 | sql_engine: QueryEngine[Any] |
| 112 | if engine is None: |
| 113 | DependencyManager.require_many( |
| 114 | "to execute sql", |
| 115 | *_default_duckdb_deps(), |
| 116 | source="kernel", |
| 117 | ) |
| 118 | sql_engine = DuckDBEngine(connection=None) |
| 119 | else: |
| 120 | for engine_cls in SUPPORTED_ENGINES: |
| 121 | if engine_cls.is_compatible(engine): |
| 122 | sql_engine = engine_cls( |
| 123 | connection=engine, engine_name=VariableName("custom") |
| 124 | ) # type: ignore |
| 125 | break |
| 126 | else: |
| 127 | raise ValueError( |
| 128 | "Unsupported engine. Must be a SQLAlchemy, Ibis, Clickhouse, DuckDB, Redshift, StarRocks or DBAPI 2.0 compatible engine." |
| 129 | ) |
| 130 | |
| 131 | try: |
| 132 | df = sql_engine.execute(query) |
| 133 | except Exception as e: |
| 134 | if is_sql_parse_error(e): |
| 135 | # NB. raising _from_ creates a noisier stack trace, but preserves |
| 136 | # the original exception context for debugging. |
| 137 | raise MarimoSQLException( |