Python Tutorial
Python MySQL - Insert Into
Add rows safely with parameterized queries, and insert many rows at once.
Insert a Single Row
Use placeholders (%s) and pass the values separately — never build SQL with string formatting. After a write you must commit() to save it.
import mysql.connector
conn = mysql.connector.connect(
host="localhost", user="root", password="secret", database="mydatabase")
cursor = conn.cursor()
sql = "INSERT INTO customers (name, address) VALUES (%s, %s)"
values = ("John", "Highway 21")
cursor.execute(sql, values)
conn.commit() # save the change
print(cursor.rowcount, "record inserted.") # 1 record inserted.Placeholders are always %s regardless of the Python type — do not add quotes around them. This is what prevents SQL injection.
Why Parameterized Queries Matter
Building SQL by concatenation lets malicious input change your query — a SQL injection attack. The driver escapes parameterized values for you.
# DANGEROUS - never do this:
# cursor.execute("INSERT INTO customers (name) VALUES ('" + name + "')")
# SAFE:
cursor.execute("INSERT INTO customers (name) VALUES (%s)", (name,))Insert Many Rows with executemany
Passing a list of tuples to executemany is far faster than a loop of single inserts.
sql = "INSERT INTO customers (name, address) VALUES (%s, %s)"
rows = [
("Peter", "Lowstreet 4"),
("Amy", "Apple st 652"),
("Hannah","Mountain 21"),
]
cursor.executemany(sql, rows)
conn.commit()
print(cursor.rowcount, "records inserted.") # 3 records inserted.Get the Inserted ID
After inserting into a table with an auto-increment key, read the new id from cursor.lastrowid.
cursor.execute("INSERT INTO customers (name) VALUES (%s)", ("Mia",))
conn.commit()
print("New id:", cursor.lastrowid)Transactions: All or Nothing
Group related writes so they either all succeed or all roll back, keeping data consistent.
try:
cursor.execute("INSERT INTO customers (name) VALUES (%s)", ("A",))
cursor.execute("INSERT INTO customers (name) VALUES (%s)", ("B",))
conn.commit() # commit both together
except mysql.connector.Error:
conn.rollback() # undo everything on any failure
raiseBest Practices
- Always use
%splaceholders — never string formatting. - Call
commit()after inserts/updates/deletes, or nothing is saved. - Use
executemanyfor bulk inserts. - Wrap multi-step writes in a try/except with
rollback().
Try It Yourself
Exercise 1: What is wrong with "INSERT INTO t (name) VALUES ('" + name + "')"?
Show solution
It is vulnerable to SQL injection. Use a placeholder instead: cursor.execute("INSERT INTO t (name) VALUES (%s)", (name,)).
Exercise 2: After inserting rows, what must you call to save them?
Show solution
conn.commit() — without it the changes are rolled back when the connection closes.
📘 Real-World Deep Dive
Knowing <strong>MySQL Insert (MySQL)</strong> well is what turns MySQL from a curiosity into a daily tool — you'll reach for it in nearly every real project.
Real-Life Scenario
An end-to-end usage of MySQL Insert that you'd actually see in a data pipeline or analytics notebook.
Real-Life Example
import mysql.connector
conn = mysql.connector.connect(database="shop")
cur = conn.cursor()
cur.executemany(
"INSERT INTO users (name, email) VALUES (%s, %s)",
[("Ada", "ada@x"), ("Bo", "bo@x")],
)
conn.commit(); print("rows:", cur.rowcount)Expected Output
(see source)Common mistakes
- Reading with the default cursor returns tuples — switch to
DictCursorfor named access. - Strings without parameter binding produce SQL-injection holes — never use f-strings in queries.
- Connecting through a long-lived daemon pool: make sure
pool_reset_connectionis on to avoid session state leakage. - Treating MySQL Insert as a black box without reading the docs — the API has subtle defaults that bite when you scale.
🚀 Performance & Best Practices
- Use prepared statements (
cursor.executemany) for bulk inserts. - Fetch with
cursor.fetchmany(1000)in streams instead offetchall(). - Use
pymysql's server-side cursors for very large result sets. - When working with MySQL, prefer vectorised / batched operations over Python loops.
🧪 Try It Yourself
- Reproduce the snippet on a representative slice of your own data.
- Profile the snippet with
cProfileortimeitand find the single biggest improvement. - Generalise the snippet into a small, reusable function you can drop into future projects.