ORM vs Raw SQL: Decision Framework

At the beginning of this series, I promised that even if you know how to use an Object Relational Mapper (ORM) to interact with a database, knowing SQL would make you a better developer. Now that we have covered everything from SELECT to parameterized queries, it is time to answer the question that every Python developer eventually asks: when should I use an ORM, and when should I just write SQL? ...

June 1, 2026 · 8 min · Jamal Hansen

Parameterized Queries & Security

As a Python developer, you are aware of software vulnerabilities. You have probably heard of SQL injection attacks, and you may have even done some work to protect against them. Today, we are going to discuss what they are and how easy it is to prevent them. SQL Injection So let’s say your application has a customer search screen. That screen allows users to search for customers by city. The user enters the city they are interested in, and you take the city they entered and make some SQL to search for customers in that city. ...

May 25, 2026 · 7 min · Jamal Hansen

Python + DuckDB: Real ETL Patterns

You’ve spent 19 posts learning SQL concepts: selecting, filtering, joining, grouping, window functions, and more. Today, you put them all together and build something real: a complete data pipeline that fetches data from an API, loads it into DuckDB, transforms it with SQL, and exports the results. What is ETL (and ELT)? This is a real-world example of a common data engineering pattern. You may have heard of ETL (Extract, Transform, Load), where data is transformed before it reaches its destination. What we are actually building today is the more modern variant, ELT: Extract, Load, Transform. ...

May 18, 2026 · 7 min · Jamal Hansen

Optimizing Queries: EXPLAIN for Python Developers

As databases grow, queries take longer to run. It’s to be expected. If your queries are consistently slow, the query itself could be the problem. We talked early in this series about SQL being a declarative language. You tell the database what you want, and it figures out how to get it. But we’ve also seen that SQL gives you the freedom to do things in many ways, and some of those ways are more efficient than others. ...

May 11, 2026 · 7 min · Jamal Hansen

Modifying Data Safely

This week, we are going to look at modifying data in a database, and I’ll be honest, it can be scary. There is no safety net, no undo button. There are some techniques you can use to minimize your risk. We will take a look at them today as we discover how to add, update, and delete data in your database. Python Comparison In Python, modifying a list is forgiving. You can append, reassign, and remove items, and if something goes wrong, your original data is usually still sitting in memory or on disk. ...

May 4, 2026 · 8 min · Jamal Hansen

Creating Tables: DDL for Python Devs

So far, we have spent our time learning how to query data. For most of us, this might be as much SQL as we will ever use. There is a whole other side to SQL used to design and define tables that are optimized to store and return data quickly. Even if you only plan to query someone else’s data, it is still helpful to get an understanding of SQL’s Data Definition Language (DDL) because it will help you to understand how the data is stored, and how to write better queries. ...

April 27, 2026 · 9 min · Jamal Hansen

Window Functions: The Feature Python Developers Miss Most

This week, we are going to focus on window functions, which are very powerful data manipulation tools. It’s something that you can do in Python, but in SQL, it is super simple and very powerful. We’ll continue using the same orders and customers tables from previous posts in our DuckDB sample database. Before I continue, I have a confession to make. While I have used window functions, I haven’t used them nearly as much as I should have. I only discovered them in the past few years. Prior to that, I used some other SQL tricks for these types of queries, but this method is much cleaner. ...

April 20, 2026 · 5 min · Jamal Hansen

NULL: The Value That Isn't

This post is about nothing, or rather, it’s about the unknown. By now, you’ve bumped into NULL several times. Let’s finally make sense of it. The SQL NULL is sort of like None in Python. After all, they both represent the lack of a value, right? value = None if value == None: # True (though `is None` is preferred) print("It's None") print(None == None) # True In Python, None is a thing you can compare. Let’s see how NULL compares. ...

April 13, 2026 · 9 min · Jamal Hansen

CTEs: Making Your SQL Readable

We learned last week about subqueries, which are like helper functions for your SQL code. They can bring back temporary values used in larger calculations or find additional data points from an id. While subqueries are very powerful, they do add complexity to your code. This complexity adds to the cognitive load when trying to read and understand your code. I’ve been the person who has to dust off an old piece of SQL code that has been running in production for years and just recently started returning invalid rows or experiencing massive latency. ...

April 6, 2026 · 5 min · Jamal Hansen

Subqueries: When SQL Needs Helper Functions

Last week, we talked about the superpower of relational databases, the ability to join tables to make data storage more efficient. In fact, we have covered much of the syntax that you would use on a daily basis already. But SQL’s simplicity hides surprising flexibility. You can model data in many ways, and you can often get the same results with different syntax. The art of SQL is optimizing your queries so that they run well. This comes with experience, so I encourage you to start playing around with the queries and data we are working with. We will see some of this flexibility with today’s topic: subqueries. ...

March 30, 2026 · 6 min · Jamal Hansen