DataSpell SQL Cells: When Notebook Convenience Becomes a Reproducibility Risk
SQL cells in DataSpell let you query a database and bind results to a pandas DataFrame inside a Jupyter notebook. Learn the trade-offs of coupling analysis to live database state, and how to keep notebooks reproducible.
14 Mar 2026, 13:51 UTC

You have a Jupyter notebook open in DataSpell, and the next step in your analysis needs a table that only exists in your team's database. You could open a separate SQL client, run the query, export a CSV, and read it back into the notebook. Or you can insert a SQL cell directly below your Python cells and keep working. The second path feels faster, and it is—until the notebook becomes the only place that query lives.
The useful takeaway: DataSpell's SQL cells are excellent for interactive exploration, but they quietly turn your notebook into an undocumented ETL job unless you treat the database boundary explicitly.
What the SQL cell actually does
In recent DataSpell releases, you can attach a database data source to a project from the Database tool window. Once that data source is configured, a Jupyter notebook in the same project can contain SQL cells alongside ordinary Python cells. The SQL cell executes against the dialect of the attached data source and returns a result grid, much like a database console would.
The feature that changes notebook workflows is the result-saving option. Instead of leaving the output in a grid, you can bind it to a Python variable—commonly a pandas DataFrame. Later Python cells can then filter, join, or plot that variable without re-issuing the query. Extraction and analysis stay in one document.
A worked example
Suppose you want the first 500 orders from the current year. In a new DataSpell project, add a data source from the Database tool window, open a Jupyter notebook, and insert a SQL cell. A small, bounded query keeps the result grid responsive:
-- Run in a DataSpell notebook SQL cell
SELECT order_id, customer_id, total_cents, created_at
FROM orders
WHERE created_at >= '2024-01-01'
LIMIT 500;
Use the cell's result-saving option to bind the output to a variable named orders_df. In the next Python cell, confirm the binding worked and inspect the shape:
# Run in a DataSpell notebook Python cell
print(type(orders_df))
print(orders_df.shape)
The practical check is straightforward: you should see that the variable is a pandas.core.frame.DataFrame and that its shape matches the row limit and column count you expect. If the type is not a DataFrame, the binding step did not complete; if the shape is unexpectedly large, your WHERE clause or LIMIT may not be filtering as intended.
The trade-off: convenience versus reproducibility
The coupling is the cost. Once a notebook depends on a SQL cell, re-running it requires the data source to be reachable and authenticated. A collaborator who opens the same notebook without the same database credentials or network access will see a failure that you do not. The notebook is no longer a self-contained artifact; it is a client of external state.
Schema drift makes this worse. If a column is renamed, dropped, or added upstream, the SQL cell may still run, but the bound DataFrame will silently change shape. Downstream Python code that references a missing column will fail, or worse, produce a subtly wrong result if the logic tolerates the change. Row counts can also shift if the underlying table is mutable.
Memory is a related risk. A broad SELECT without a tight LIMIT or aggregation materializes the full result set in the notebook kernel and the browser grid. On a large table, that can exhaust memory long before the analysis begins.
Drawing a practical boundary
None of this means SQL cells are bad. It means they belong at a specific point in the workflow. Treat the SQL cell as an exploratory convenience: use it to profile data, test a join, or sketch a transformation. When the query stabilizes, promote it out of the notebook.
There are two common destinations. For repeatable analysis, cache the extract to a versioned file such as Parquet and read that file in the notebook. This decouples the notebook from live database state while keeping the data local. For production logic, move the final query into a scheduled ETL job or a versioned SQL model so the notebook consumes a stable contract rather than a live table.
A direct way to test your notebook's coupling is to disconnect the data source and re-run the notebook from top to bottom. If it fails at the SQL cell, you have confirmed the dependency. At that point, decide whether the notebook is a scratchpad that documents its requirements, or whether it needs a cached snapshot to be reproducible.
An actionable closing check
Before you share a DataSpell notebook that contains SQL cells, ask one question: if the database were unreachable, would this notebook still run? If the answer is no, either document the data source and credential requirements clearly, or materialize the extract to Parquet and point the notebook at the file. The SQL cell is a powerful tool for keeping extraction close to analysis—just make sure the notebook does not become the only place the truth lives.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.