Why connect Python to a database?
Python is good at logic and user screens; MySQL is good at storing and searching lots of data safely. Together, a Python program (the front end) can store and read data in MySQL (the back end).
Install the connector once: pip install mysql-connector-python. Then:
import mysql.connector as sql
Step by step: connect, cursor, execute
import mysql.connector as sql
con = sql.connect(host='localhost', user='root',
passwd='your_password', database='school')
if con.is_connected():
print('Connected')
cur = con.cursor()
cur.execute('SELECT * FROM student')- connect() returns a connection object. Arguments:
host(the server, often 'localhost'),user,passwd/password,database. is_connected()returns True if the connection works.- cursor() makes a cursor object from the connection. It runs queries and holds the result set.
- execute(query) sends one SQL statement as a string.
Reading results: fetchone, fetchall, fetchmany, rowcount
After a SELECT, the rows wait in the cursor's result set. Each row comes as a tuple.
fetchone(): the next single row as a tuple, orNonewhen no rows are left.fetchall(): all remaining rows as a list of tuples (empty list if none left).fetchmany(n): the next n rows as a list.rowcount: a property (no brackets). For SELECT it is the number of rows fetched so far; for INSERT/UPDATE/DELETE it is the number of rows affected.
cur.execute('SELECT RollNo, Name FROM student')
r = cur.fetchone() # (1, 'Asha')
print(cur.rowcount) # 1
rest = cur.fetchall() # [(2,'Ravi'), (3,'Zoya')]
print(cur.rowcount) # 3
for row in rest:
print(row[0], row[1])
Changing data: INSERT, UPDATE, DELETE and commit()
cur.execute("INSERT INTO student VALUES (4, 'Om', 'Pune', 70)")
con.commit()
print(cur.rowcount, 'row inserted')
cur.execute('UPDATE student SET Marks = Marks + 2 WHERE Marks < 60')
con.commit()
print(cur.rowcount, 'rows updated')commit() belongs to the connection (con.commit()), not the cursor. It makes the changes permanent. Without it, changes are thrown away when the program ends. (con.rollback() undoes changes not yet committed.) Finally: cur.close() and con.close().
Putting values into queries: %s and format()
Using %s placeholders (preferred)
roll = int(input('Roll: '))
cur.execute('SELECT * FROM student WHERE RollNo = %s', (roll,))
print(cur.fetchone())
cur.execute('INSERT INTO student VALUES (%s, %s, %s, %s)', (5, 'Kabir', 'Jaipur', 66))
con.commit()Values go in a tuple as the second argument. A single value still needs a comma: (roll,). The connector adds quotes where needed and protects against harmful input (SQL injection). Always write %s, even for numbers.
Using format() or f-strings
q = "SELECT * FROM student WHERE Marks > {} AND City = '{}'".format(80, 'Delhi')
cur.execute(q)Here the string is built first, so you must add quotes around text values yourself. It is fine for practice, but %s is safer for real input.
Try it: a mini menu program
Write a menu: 1 Add student, 2 Show all, 3 Search by roll, 4 Exit. Use execute with %s for add and search, commit() after add, fetchall() for show and fetchone() for search. Test: add a student and forget commit(); restart and see it is missing. Then add commit() and try again. Use the 3D free-play step to predict what fetchone and fetchall return.
Key formulas and definitions
- con = mysql.connector.connect(host, user, passwd, database) โ cur = con.cursor()
- cur.execute(sql[, params]) ยท con.commit() after INSERT/UPDATE/DELETE
- fetchone() โ tuple or None ยท fetchall() โ list of tuples ยท fetchmany(n) ยท cur.rowcount
- execute('โฆ %s โฆ', (value,)) ยท or 'โฆ {} โฆ'.format(value)
Worked examples
1. Write code to connect to database 'library' on localhost as user 'root' with password 'abc' and print whether it is connected.
import mysql.connector as sql con = sql.connect(host='localhost', user='root', passwd='abc', database='library') print(con.is_connected()) # True
2. Table student has 5 rows. After cur.execute('SELECT * FROM student'), the code calls fetchone() twice and then fetchall(). How many rows does fetchall() return, and what is cur.rowcount at the end?
fetchone() twice takes rows 1 and 2. fetchall() returns the remaining 3 rows. rowcount = 5 (all rows fetched so far).
3. Display all students with Marks above 80 using %s.
cur.execute('SELECT Name, Marks FROM student WHERE Marks > %s', (80,)) for name, marks in cur.fetchall(): print(name, marks)
4. Insert a student whose details are typed by the user, then save.
r = int(input('Roll: ')); n = input('Name: '); c = input('City: '); m = int(input('Marks: ')) cur.execute('INSERT INTO student VALUES (%s, %s, %s, %s)', (r, n, c, m)) con.commit() print(cur.rowcount, 'record added')
5. Write the same search using format(): show students from a city typed by the user.
city = input('City: ') q = "SELECT * FROM student WHERE City = '{}'".format(city) cur.execute(q) print(cur.fetchall()) # note the quotes around {} for text
6. A program runs cur.execute('DELETE FROM student WHERE Marks < 40') and then closes, but the rows are still in the table. Why? Fix it.
The change was never committed. Add con.commit() after execute, then close: con.commit(); cur.close(); con.close().
Common mistakes
- Forgetting con.commit() after INSERT, UPDATE or DELETE, so nothing is saved.
- Writing cur.commit(); commit() belongs to the connection object.
- Passing a single value as (80) instead of (80,); it must be a tuple.
- Calling rowcount() with brackets; it is a property: cur.rowcount.