Skip to content

Commit 78b799e

Browse files
Merge pull request #169 from LaunchCodeEducation/databases-python
audit for pandas | python databases
2 parents 3a5d964 + ec787ff commit 78b799e

3 files changed

Lines changed: 90 additions & 15 deletions

File tree

content/python-pandas-databases/_index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title = "Databases with Python and pandas"
44
date = 2024-04-17T10:00:24-05:00
55
draft = false
66
weight = 23
7-
hidden = false
7+
hidden = true
88
+++
99

1010
## Learning Objectives

content/python-pandas-databases/reading/pandas-databases/_index.md

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ This lesson will also utilize `sqlite3` as the database used to demonstrate how
1414
- Adding the DataFrame data into the new table
1515

1616
{{% notice red Warning "rocket" %}}
17-
We have created a new repo for Class 19 and 20 exercises and studios.
17+
We have created a new repo for Class 19 and 20 exercises and studios (Class numbers may differ per cohort).
1818
Please fork this repo to your Github account, and then clone it to your local device
1919

2020
[Class 19 and 20 Exercise Studio Repo](https://github.com/LaunchCodeEducation/data-analysis-projects-class-19-and-20)
@@ -56,26 +56,22 @@ new_movie = pd.DataFrame([{'title':'Dune', 'genre':'Science Fiction', 'release':
5656
df = pd.concat([df, new_movie], ignore_index=True)
5757
```
5858

59-
It isn't necessary for us to update our DataFrame to add a new table to the database.
59+
It isn't necessary for us to update our DataFrame to add a new table to the database.
6060
But, it will help visually when reading data to show that it was populated into a new table correctly.
6161

62-
```python {linenos=table}
62+
```python
6363
# Inject dataframe into database as new table, if the table exists - replace it
64-
df.to_sql('df', movies_db, if_exists="replace")
65-
# Execute command to create a new table called new_movie_table with the new_movie dataframe data
66-
movies_db.execute(
67-
"""
68-
create table new_movie_table as
69-
select * from new_movie
70-
"""
71-
)
64+
# Use index=False to avoid storing the DataFrame index as a column
65+
df.to_sql('updated_movies', movies_db, if_exists="replace", index=False)
66+
# Commit the changes to the database
67+
movies_db.commit()
7268
```
7369

7470
The pandas `DataFrame.to_sql` function documentation in the above code block can be found here: [pandas.DataFrame.to_sql](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_sql.html)
7571

7672
```python
7773
# Read data from newly created table, passing in existing movies_db connection as parameter
78-
new_movies_df = pd.read_sql_query('Select * from new_movie_table;', movies_db)
74+
new_movies_df = pd.read_sql_query('SELECT * FROM updated_movies;', movies_db)
7975
# Read first 6 rows
8076
new_movies_df.head(6)
8177
```

content/python-pandas-databases/reading/python-databases/_index.md

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,26 @@ Working within a database command line interface can oftentimes make it cumberso
1212

1313
While you can accomplish more than just the above using python and pandas, like performing joins, it is not always best practice. As it relates to joins, database engines are built and optimized to perform joins extremely well. It is always important to know what you will be doing with your data before acting.
1414

15+
## When to Use sqlite3 vs pandas
16+
17+
Understanding when to use each tool will help you write more efficient code:
18+
19+
**Use sqlite3 directly when:**
20+
- Performing complex SQL operations (joins, aggregations, subqueries)
21+
- Working with large datasets that don't fit in memory
22+
- You need precise control over transactions and commits
23+
- Creating or modifying database schema (tables, indexes, constraints)
24+
- The data will remain in the database without further analysis
25+
26+
**Use pandas when:**
27+
- You need to perform complex data analysis or visualization
28+
- Applying statistical operations or transformations
29+
- Cleaning and reshaping data
30+
- Integrating database data with other data sources
31+
- The dataset is small to medium-sized and fits in memory
32+
33+
**Best Practice:** Use sqlite3 to filter and join data in the database, then load the results into pandas for analysis. This leverages the strengths of both tools!
34+
1535
{{% notice red Warning "rocket" %}}
1636
We have created a new repo for Class 19 and 20 exercises and studios.
1737
Please fork this repo to your Github account, and then clone it to your local device
@@ -63,6 +83,26 @@ The basic syntax for executing a command with the cursor object is as follows:
6383
cur.execute("SQL statement")
6484
```
6585

86+
## Using Context Managers
87+
88+
A better practice for managing database connections is to use Python's context manager pattern with the `with` statement. This ensures that connections are properly closed even if an error occurs:
89+
90+
{{% notice blue Example "rocket" %}}
91+
```python
92+
import sqlite3
93+
94+
# Using a context manager - connection closes automatically
95+
with sqlite3.connect('Movies.db') as movies_db:
96+
cur = movies_db.cursor()
97+
cur.execute("SELECT * FROM movies")
98+
results = cur.fetchall()
99+
print(results)
100+
# Connection is automatically closed here
101+
```
102+
103+
This pattern is especially useful when performing multiple operations, as it guarantees proper cleanup.
104+
{{% /notice %}}
105+
66106
## Creating a table
67107

68108
```python
@@ -76,7 +116,9 @@ You can find a list of SQLite data types here: [Data Types in SQLite](https://sq
76116
### Insert Table Values
77117

78118
```python
79-
cur.execute("INSERT INTO table_name ('value-one', 'value-two', etc..)")
119+
cur.execute("INSERT INTO table_name (column1, column2) VALUES ('value-one', 'value-two')")
120+
# Commit the changes to save them to the database
121+
movies_db.commit()
80122
```
81123

82124
### Reading Data
@@ -87,7 +129,7 @@ There are a couple strategies that you can use to read data from your database.
87129

88130
```python
89131
# For loop to iterate over cursor object
90-
for row in cur.execute("SELECT column FROM table_name")
132+
for row in cur.execute("SELECT column FROM table_name"):
91133
print(row)
92134
```
93135

@@ -113,6 +155,8 @@ update_release_year = 1997 # Value that needs to be updated
113155
movie_to_update = 'Good Will Hunting'
114156
# Execute an UPDATE statement using the ? placeholder, passing in the update variables as a list literal
115157
cur.execute("UPDATE movies SET release = ? WHERE title = ?", [update_release_year, movie_to_update])
158+
# Commit the changes to save them to the database
159+
movies_db.commit()
116160
```
117161
{{% /notice %}}
118162

@@ -126,9 +170,44 @@ Using parameterized queries to update and delete data is a best practice!
126170
movie_to_delete = 'Inception' # Too many sci fi movies!
127171
# Execute a DELETE statement using the ? placeholder, passing in the variable as a list literal
128172
cur.execute("DELETE FROM movies WHERE title = ?", [movie_to_delete])
173+
# Commit the changes to save them to the database
174+
movies_db.commit()
129175
```
130176
{{% /notice %}}
131177

178+
## Error Handling
179+
180+
When working with databases, it's important to handle potential errors gracefully. Common errors include trying to access tables that don't exist, constraint violations, or connection issues.
181+
182+
{{% notice blue Example "rocket" %}}
183+
```python
184+
import sqlite3
185+
186+
try:
187+
with sqlite3.connect('Movies.db') as movies_db:
188+
cur = movies_db.cursor()
189+
190+
# Attempt to insert a duplicate record or violate a constraint
191+
cur.execute("INSERT INTO movies (title, genre, release) VALUES (?, ?, ?)",
192+
['Inception', 'Sci-Fi', 2010])
193+
movies_db.commit()
194+
195+
except sqlite3.IntegrityError as e:
196+
print(f"Database integrity error: {e}")
197+
198+
except sqlite3.OperationalError as e:
199+
print(f"Database operational error (table may not exist): {e}")
200+
201+
except sqlite3.Error as e:
202+
print(f"Database error: {e}")
203+
204+
except Exception as e:
205+
print(f"Unexpected error: {e}")
206+
```
207+
208+
Using try-except blocks helps your program handle errors without crashing and provides useful feedback.
209+
{{% /notice %}}
210+
132211
## Check Your Understanding
133212

134213
{{% notice green Question "rocket" %}}

0 commit comments

Comments
 (0)