Free Study Material

Python-SQL Interface

Introduction

You already know how to write a SELECT query directly in SQL. Python and MySQL are two separate programs, though — connecting them needs a bridge, so a Python program can send that same kind of query and get results back as ordinary Python data. The mysql.connector module is that bridge.

Concept

Two objects work together for every database interaction:

  • Connection — represents the actual link between Python and the MySQL server (created with your host, username, password, and database name).
  • Cursor — created from a Connection, and is the object that actually executes queries and retrieves their results. Think of the Connection as the phone line, and the Cursor as the person talking through it.

Worked Example

import mysql.connector

mydb = mysql.connector.connect(
    host="localhost",
    user="root",
    password="password",
    database="school"
)

mycursor = mydb.cursor()
mycursor.execute("SELECT * FROM STUDENT")

result = mycursor.fetchall()
for row in result:
    print(row)

mycursor.execute("SELECT * FROM STUDENT")
first_row = mycursor.fetchone()
print("Just one row:", first_row)

fetchall() returns every matching row as a list of tuples — one tuple per row, exactly matching how you'd already expect a SQL row to look. fetchone() instead returns just a single tuple — the next unread row from the same query — which is why execute() is called a second time above, to give fetchone() a fresh result set to read from.

Note: fetchone() returns just the next single row; fetchall() returns every remaining row at once, as a list. Both are read from the SAME cursor after execute() runs a SELECT.

Summary

A Connection links Python to the MySQL server; a Cursor, created from it, executes queries and retrieves results. fetchall() returns every row as a list of tuples — the standard way Python code reads back SQL query results.

Interfacing Python with MySQL

Python natively doesn't understand SQL. To make them talk, we need a driver called mysql.connector and a specific 4-step sequence.

1
Connect

Establish the link using mysql.connector.connect().

2
Cursor

Create a cursor object. This is the "Worker" that travels to the database to execute queries.

3
Execute

Run the SQL command using cursor.execute("SELECT...").

4
Fetch

Retrieve results using fetchall() or fetchone().

Handling Results (Fetch)

When you run a SELECT query, MySQL sends back a table. Python converts this table into a List of Tuples.

MySQL Database

ID Name
1Ravi
2Amit

cursor.fetchall()

Python Output

[
  (1, 'Ravi'),
  (2, 'Amit')
]

(A List of Tuples)

Fetch Methods

  • fetchall(): Returns ALL rows (List of Tuples).
  • fetchone(): Returns ONE row (Single Tuple) or None.
  • rowcount: Returns the number of rows affected/retrieved.
import mysql.connector

# 1. Connect
mydb = mysql.connector.connect(
  host="localhost",
  user="root",
  password="1234",
  database="school"
)

# 2. Cursor
mycursor = mydb.cursor()

# 3. Execute
mycursor.execute("SELECT * FROM Student")

# 4. Fetch
data = mycursor.fetchall()

for row in data:
  print(row)

Challenge: Fill in the Blanks

Identify the correct methods for the following tasks:

1. To create a connection object: connect()
2. To execute a SQL query: __________
3. To get all records as a list: __________
4. To get a single record: __________

Introduction

Reading data with SELECT is only half of Python-SQL connectivity — actually changing data (INSERT, UPDATE, DELETE) from Python needs one extra, easy-to-forget step, plus a real security habit worth building from the start.

Concept

After executing a data-changing query, you must call mydb.commit() on the Connection object (not the cursor) — without it, MySQL treats the change as temporary and it is never actually saved to the database.

Worked Example

import mysql.connector

mydb = mysql.connector.connect(host="localhost", user="root", password="password", database="school")
mycursor = mydb.cursor()

name = input("Enter name: ")
marks = input("Enter marks: ")

# %s placeholders -- NEVER build the query with f-strings/string concatenation
sql = "INSERT INTO STUDENT (Name, Marks) VALUES (%s, %s)"
mycursor.execute(sql, (name, marks))

mydb.commit()
print("Record inserted successfully.")
Warning: Building a query with an f-string like f"INSERT INTO STUDENT VALUES ('{name}')" is a real SQL Injection risk — a malicious value typed as input could alter the query's meaning entirely. The %s placeholder style, with values passed separately to execute(), is what actually prevents this.

Summary

mycursor.execute(sql, values) runs an INSERT/UPDATE/DELETE, but mydb.commit() — called on the Connection, not the Cursor — is what actually saves the change permanently. Using %s placeholders instead of building queries with string formatting is what protects against SQL Injection.

Writing Changes to the Database

Fetching data (SELECT) is safe—you just look at it.
But when you Insert, Update, or Delete, you are changing the database. Python requires an extra step called Commit to make these changes permanent.

1. Pending State

(After cursor.execute)

Visible only to Python
db.commit()

2. Permanent State

(Saved in MySQL)

Visible to Everyone
Crucial Warning:

If you forget db.commit() after an INSERT/UPDATE/DELETE, your data will NOT be saved!

Secure Queries with `%s`

Never use string formatting (f-strings) to put user data directly into a query. It is dangerous (SQL Injection).
Instead, use the %s placeholder.

The Dangerous Way

String formatting allows hackers to break your database.

sql = f"INSERT INTO St VALUES ('{name}')"
The Safe Way (%s)

Let Python handle the quotes safely.

sql = "INSERT INTO St VALUES (%s)" val = (name, )
import mysql.connector

# 1. Connect
mydb = mysql.connector.connect(host="localhost", user="root", password="1234", database="school")
mycursor = mydb.cursor()

# 2. Prepare Query (Notice the %s)
sql = "INSERT INTO Student (Name, Marks) VALUES (%s, %s)"
val = ("Neha", 98)

# 3. Execute
mycursor.execute(sql, val)

# 4. Commit (Make it Permanent)
mydb.commit()

# 5. Verify
print(mycursor.rowcount, "record inserted.")

Challenge: Find the Bug

A student wrote this code to add a record, but the database remains empty. Why?

cursor.execute("INSERT INTO Emp VALUES (101, 'Ravi')")
print("Done!")
Missing: ______________________

Want the full course?

Unlock all chapters, video lectures, and SQL practice exercises.

Get Full Access