You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 3_sql-and-python.md
+69-18Lines changed: 69 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -116,7 +116,7 @@ Read in the birds.csv file using Apache Arrow, then use the DuckDB Python librar
116
116
```{admonition} Exercise 3.02
117
117
118
118
Use the DuckDB Python client to return these results as a Polars dataframe.
119
-
119
+
```
120
120
```sql
121
121
SELECT
122
122
Species_Common_Name,
@@ -125,18 +125,79 @@ SELECT
125
125
AVG(Beak_Length_Culmen) AS Avg_Beak_Length_Culmen
126
126
FROM'birds.csv'
127
127
GROUP BY Species_Common_Name
128
-
129
128
```
129
+
130
130
```{code-cell}
131
131
# Uncomment and run to show solution
132
132
# !cat ./answers/answer_3.02.py
133
133
```
134
134
135
-
## 2. Using `ibis` with a DuckDB backend
135
+
## 2. Using the DuckDB Relational API
136
+
137
+
In addition to SQL, you can write DuckDB queries using the built-in relational API.
138
+
We'll see how to chain functions together to build up a query.
139
+
DuckDB will then combine that function chain together into a single query, so you still get all of DuckDB's query optimization (speed and scalability!) benefits.
140
+
141
+
The question we will build up towards answering is, "Who were the most prolific people at finding many new species of non-extinct ducks, and when did they get started finding ducks?"
142
+
143
+
<!-- TODO: Add in a few incremental steps as examples -->
144
+
145
+
The Relational API has a `read_csv` function that mirrors the Pandas function of the same name.
146
+
These methods can be called on DuckDB connection objects or the default connection using the duckb object itself.
147
+
148
+
As a note, if we wrap our relational expressions in a set of parentheses, we can organize them nicely across multiple lines.
149
+
150
+
Here, we `filter` using an expression much like we would use in a `where` clause to only non-extinct ducks.
151
+
The, we use `aggregate` to execute a `group by` operation, grouping by the `author` column.
152
+
Lastly, we `order` by one of the aggregate expression columns.
153
+
154
+
```{code-cell}
155
+
duck_legends = (duckdb
156
+
.read_csv("ducks.csv")
157
+
.filter("extinct = 0")
158
+
.aggregate("author, count(name) as count_name, min(year) as min_year", "author")
159
+
.order("count_name desc")
160
+
)
161
+
duck_legends
162
+
```
163
+
164
+
You can also see the SQL that is generated using with `sql_query()` function:
165
+
```{code-cell}
166
+
print(duck_legends.sql_query())
167
+
```
168
+
169
+
Much like DuckDB can query DataFrames within SQL as if they were tables, it can also do the same for relation objects.
170
+
171
+
```{code-cell}
172
+
duckdb.sql("select * from duck_legends limit 5")
173
+
```
174
+
175
+
Technically, the `.sql` function returns a relation object as well, so you can also chain relational operations after a SQL one also!
176
+
177
+
As a silly example, we could run:
178
+
179
+
```{code-cell}
180
+
duckdb.sql("select * from duck_legends limit 5").limit(1)
181
+
```
182
+
183
+
Now we can mix and match SQL and the relational API!
184
+
185
+
```{admonition} Exercise 3.04
186
+
As an exercise, use SQL to initially pull the CSV file, but then chain together the remaining Relational operators from the `duck_legends` example above to return the same result.
187
+
```
188
+
189
+
```{code-cell}
190
+
# Uncomment and run to show solution
191
+
# !cat ./answers/answer_3.03.py
192
+
```
193
+
194
+
## 3. Using `ibis` with a DuckDB backend
136
195
137
196
### A. Introduction to Ibis and DuckDB
138
197
139
-
We'll show you how to leverage the power of DuckDB without even needing to write a single line of SQL. Instead, we'll use Ibis, a powerful Python library that allows you to interact with databases using a DataFrame-like syntax. We'll also show you how to combine the two so you can get the best of both worlds.
198
+
Another option for using DuckDB is Ibis, a powerful Python library that allows you to interact with databases using a DataFrame-like syntax. We'll also show you how to combine the SQL and Ibis so you can get the best of both worlds.
199
+
200
+
Ibis also works across many different databases, so you can write your code once and run it on a variety of database engines.
140
201
141
202
First, let's make sure you have the necessary packages installed. You can install DuckDB and Ibis using pip:
Now that we have a table set up, let's see how we can query this data using Ibis. With Ibis, you can perform operations on your data without writing SQL. Let's see how similar it feels...
238
+
Now that we have a table set up, let's see how we can query this data using Ibis. Let's see how similar it feels...
178
239
179
-
The question we will build up towards answering is, "Who were the most prolific people at finding many new species of non-extinct ducks, and when did they get started finding ducks?"
240
+
We will answer the same question as with the relational API: "Who were the most prolific people at finding many new species of non-extinct ducks, and when did they get started finding ducks?"
180
241
181
242
Use the `filter` function instead of a `where` clause to choose the rows you are interested in. Ibis also uses Python's `==` comparators instead of SQL's single `=`.
Pick your columns using the conveniently named `select` function!
188
245
189
-
```{code-cell}
190
-
(persistent_ducks
191
-
.filter(persistent_ducks.extinct == 0)
192
-
.select("name", "author", "year")
193
-
)
194
-
```
195
-
196
246
The `group_by` functions matches well with the `group by` clause.
197
247
198
248
However, Ibis splits the `select` clause into the `select` function and the `aggregate` function when working with a group by. This aligns with the SQL best practice to organize your `select` clause with non-aggregate expressions first, then aggregate expressions.
@@ -247,6 +297,7 @@ duck_legends
247
297
248
298
And there you go! You've learned:
249
299
* How to read and write Pandas, Polars, and Apache Arrow with DuckDB
300
+
* How to use DuckDB's Relational API and how to combine it with SQL
250
301
* How to use Ibis to run dataframe queries on top of DuckDB
251
302
* How to see the SQL that Ibis is running on your behalf
252
303
* How to mix and match SQL and Ibis
@@ -255,6 +306,7 @@ And there you go! You've learned:
255
306
```{admonition} Exercise 3.04
256
307
257
308
Convert the SQL query below into an Ibis expression. You are welcome to ignore the column renaming - think of it as a "stretch-goal" if you have time! We did not cover how to do that yet.
0 commit comments