Skip to content
AgileLogics
6 min read

Using SQL from Application Code

Prerequisites: Inserting data, Constraints and foreign keys

Most SQL runs inside applications: a web app looks up a user, saves an order, or builds a report. Every language has a library for this.

Parameterized queries — always

Never build SQL by gluing user input into a string. Pass values as parameters instead, and the database driver keeps data and code separate.

In Python, with the built-in sqlite3 module:

import sqlite3

conn = sqlite3.connect("shop.db")
email = input("Email: ")

# DANGEROUS — SQL injection:
# conn.execute(f"SELECT * FROM customers WHERE email = '{email}'")

# Safe — the ? is a placeholder:
row = conn.execute("SELECT id, name FROM customers WHERE email = ?", (email,)).fetchone()
print(row)

In PHP, with PDO:

$pdo = new PDO('sqlite:shop.db');
$stmt = $pdo->prepare('SELECT id, name FROM customers WHERE email = :email');
$stmt->execute(['email' => $email]);
$customer = $stmt->fetch(PDO::FETCH_ASSOC);

What SQL injection looks like

If code builds "... WHERE email = '" + email + "'" and a user types:

' OR '1'='1

the query becomes WHERE email = '' OR '1'='1' — which is true for every row, exposing every customer. Other inputs can delete tables. With parameters, that input is just an odd email address that matches nothing. SQL injection is one of the most common and damaging security bugs — and parameters prevent it completely.

ORMs and query builders

Many frameworks provide an ORM (object-relational mapper) that maps tables to classes and writes common SQL for you: Laravel's Eloquent, Django's ORM, SQLAlchemy, Entity Framework, Hibernate, ActiveRecord, Prisma. They use parameters automatically and save a lot of repetitive code.

Knowing SQL still matters: ORMs generate SQL you'll need to read when debugging slow pages, and complex reports are often clearer in plain SQL.

The N+1 query problem

A classic ORM mistake: loading 100 orders, then running one query per order to fetch its customer — 101 queries instead of 1 or 2. Use a join, or the ORM's "eager loading" feature (with('customer'), select_related, includes), to fetch related data in bulk.

Connections

Opening a database connection is slow. Applications reuse connections from a connection pool, and close them when finished. Keep transactions short, and don't hold a connection open while waiting on a user or an external API.