Skip to content

Commit 7f06533

Browse files
author
Saurabh Badenkal
committed
End-to-end SQL support: schema discovery, SELECT * expansion, DataFrame bridge, guardrails, examples
- Schema discovery APIs: list_columns, list_relationships, list_table_relationships - SELECT * auto-expansion via list_columns (server blocks SELECT *) - client.dataframe.sql() for SQL -> DataFrame bridge - SQL safety guardrails: block writes, auto-inject TOP 5000, warn on leading-wildcard LIKE and implicit cross joins - Comprehensive sql_examples.py (28 sections): JOINs, aggregates, GROUP BY, DISTINCT, OFFSET FETCH, polymorphic lookups, audit trail, SQL read -> DataFrame transform -> SDK write-back - Updated query.sql() docstring with accurate SQL capabilities - 732 tests (was 318), all passing
1 parent d61ffca commit 7f06533

File tree

12 files changed

+2030
-15
lines changed

12 files changed

+2030
-15
lines changed

README.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,14 @@ client.dataframe.update("account", df, id_column="accountid", clear_nulls=True)
269269

270270
# Delete records by passing a Series of GUIDs
271271
client.dataframe.delete("account", new_accounts["accountid"])
272+
273+
# SQL query directly to DataFrame (supports JOINs, aggregates, GROUP BY)
274+
df = client.dataframe.sql(
275+
"SELECT a.name, COUNT(c.contactid) as contacts "
276+
"FROM account a "
277+
"JOIN contact c ON a.accountid = c.parentcustomerid "
278+
"GROUP BY a.name"
279+
)
272280
```
273281

274282
### Query data
@@ -372,14 +380,30 @@ results = (client.query.builder("account")
372380
.execute())
373381
```
374382

375-
**SQL queries** provide an alternative read-only query syntax:
383+
**SQL queries** provide an alternative read-only query syntax with support for
384+
JOINs, aggregates, GROUP BY, DISTINCT, and OFFSET FETCH pagination:
376385

377386
```python
387+
# Basic query
378388
results = client.query.sql(
379389
"SELECT TOP 10 accountid, name FROM account WHERE statecode = 0"
380390
)
381-
for record in results:
382-
print(record["name"])
391+
392+
# JOINs and aggregates work
393+
results = client.query.sql(
394+
"SELECT a.name, COUNT(c.contactid) as cnt "
395+
"FROM account a "
396+
"JOIN contact c ON a.accountid = c.parentcustomerid "
397+
"GROUP BY a.name"
398+
)
399+
400+
# SELECT * is auto-expanded by the SDK
401+
results = client.query.sql("SELECT * FROM account")
402+
403+
# SQL results directly as a DataFrame
404+
df = client.dataframe.sql(
405+
"SELECT name, revenue FROM account ORDER BY revenue DESC"
406+
)
383407
```
384408

385409
**Raw OData queries** are available via `records.get()` for cases where you need direct control over the OData filter string:

examples/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ Deep-dive into production-ready patterns and specialized functionality:
4040
- Column metadata management and multi-language support
4141
- Interactive cleanup and best practices
4242

43+
- **`sql_examples.py`** - **SQL QUERY END-TO-END** 🔍
44+
- Schema discovery before writing SQL (list_columns, list_relationships)
45+
- Full SQL capabilities: SELECT, WHERE, TOP, ORDER BY, LIKE, IN, BETWEEN
46+
- JOINs (INNER, LEFT, multi-table), GROUP BY, DISTINCT, aggregates
47+
- OFFSET FETCH for server-side pagination
48+
- SELECT * auto-expansion (SDK rewrites for server compatibility)
49+
- Polymorphic lookups via SQL (ownerid, customerid, createdby)
50+
- SQL read -> DataFrame transform -> SDK write-back (full round-trip)
51+
- SQL-driven bulk create, update, and delete patterns
52+
- SQL to DataFrame via `client.dataframe.sql()`
53+
- Limitations with SDK fallbacks (writes, subqueries, functions)
54+
- Complete reference table: SQL vs SDK method mapping
55+
4356
- **`file_upload.py`** - **FILE OPERATIONS** 📎
4457
- File upload to Dataverse file columns with chunking
4558
- Advanced file handling patterns
@@ -68,13 +81,17 @@ python examples/basic/functional_testing.py
6881
```bash
6982
# Comprehensive walkthrough with production patterns
7083
python examples/advanced/walkthrough.py
84+
85+
# SQL queries end-to-end with SDK fallbacks for unsupported operations
86+
python examples/advanced/sql_examples.py
7187
```
7288

7389
## 🎯 Quick Start Recommendations
7490

7591
- **New to the SDK?** → Start with `examples/basic/installation_example.py`
7692
- **Need to test/validate?** → Use `examples/basic/functional_testing.py`
7793
- **Want to see all features?** → Run `examples/advanced/walkthrough.py`
94+
- **Using SQL queries?** → Run `examples/advanced/sql_examples.py`
7895
- **Building production apps?** → Study patterns in `examples/advanced/walkthrough.py`
7996

8097
## 📋 Prerequisites

0 commit comments

Comments
 (0)