Class 12 Informatics Practices Chapter 04 ยท 21 min read

๐Ÿ“˜ Importing/Exporting Data (CSV & MySQL)

Unit 1 ยท Ch 4 Oct 12, 2026
Chapter Quiz Share

So far, all our data has lived only inside Python โ€” the moment you close your program, everything vanishes! This chapter teaches you how to save data permanently (to CSV files or MySQL databases) and load it back whenever you need it. Real applications such as a school's result portal or a shop's billing software work the same way.

๐Ÿ’ก How to use these notes

Focus on read_csv() and to_csv() first โ€” they are the core of this chapter. Then move to MySQL sections. Every code example here is meant to be typed and run โ€” don't just read! ๐ŸŽฏ


4.1 ๐ŸŒŸ Introduction

Imagine you spend 2 hours in Python creating a DataFrame of 100 students' marks. You close your laptop. Next morning โ€” all that data is GONE! Why? Because Python variables only exist while the program is running โ€” this is called temporary memory (RAM).

graph LR
    PY["๐Ÿ Python Program\nRunning..."]
    RAM["๐Ÿ’ญ Data in RAM\n(Temporary Memory)"]
    CLOSE["โŒ Program Closes"]
    GONE["๐Ÿ˜ฑ Data LOST!"]

    PY --> RAM --> CLOSE --> GONE

    style RAM fill:#FF9800,color:#fff
    style GONE fill:#F44336,color:#fff

The Solution: Persistence! We save data to permanent storage โ€” either a simple CSV file or a MySQL database โ€” so it survives even after you close Python.

graph LR
    PY["๐Ÿ Python\nDataFrame"]
    CSV["๐Ÿ“„ CSV File\n(Permanent!)"]
    SQL["๐Ÿ—„๏ธ MySQL Database\n(Permanent!)"]

    PY -->|"to_csv()"| CSV
    CSV -->|"read_csv()"| PY
    PY -->|"to_sql()"| SQL
    SQL -->|"read_sql()"| PY

    style CSV fill:#4CAF50,color:#fff
    style SQL fill:#2196F3,color:#fff
๐Ÿ’พ

Persistence

Data survives even after closing the program

Like saving a Word document โ€” it doesn't disappear!
๐Ÿ“„

CSV File

Simple text file storing data in rows/columns

Like a basic Excel sheetbut plain text
๐Ÿ—„๏ธ

MySQL Database

Powerful, organised storage system

Like a bank's data storage โ€” highly reliable
๐Ÿ”„

Import/Export

Moving data IN and OUT of Python

Import = bring data inExport = save data out

Real-World Analogy: Writing on a whiteboard is like storing data in RAM โ€” erase the board (close Python), everything is gone. Writing in your notebook is like saving to a CSV file or MySQL database โ€” it stays there forever, even after you close your bag!


4.2 ๐Ÿ“„ Transferring Data between .csv Files and DataFrames

What is a CSV file? ๐Ÿค”

CSV = Comma Separated Values. It's the SIMPLEST way to store table data โ€” just plain text where:

  • Each line = one row
  • Commas separate the columns
RollNo,Name,Marks
1,Amit,85
2,Neha,90
3,Raj,78

That's it! No fancy formatting โ€” just text with commas. You can even open a CSV file in Notepad!

graph LR
    EXCEL["๐Ÿ“Š Looks like Excel\nwhen opened in\nExcel/Sheets"]
    NOTEPAD["๐Ÿ“ Looks like plain text\nwhen opened in\nNotepad"]
    CSV["๐Ÿ“„ SAME .csv FILE"]

    CSV --> EXCEL
    CSV --> NOTEPAD

    style CSV fill:#FF9800,color:#fff

4.2.1 Loading Data from CSV to DataFrames ๐Ÿ“ฅ

The function pd.read_csv() reads a CSV file and instantly converts it into a Pandas DataFrame!

Sample file: students.csv

RollNo,Name,Marks,City
1,Amit,85,Delhi
2,Neha,90,Mumbai
3,Raj,78,Delhi
4,Priya,92,Pune
# read_csv_basic.py
import pandas as pd

df = pd.read_csv("students.csv")
print(df)

Output:

   RollNo   Name  Marks    City
0       1   Amit     85   Delhi
1       2   Neha     90  Mumbai
2       3    Raj     78   Delhi
3       4  Priya     92    Pune

That's it โ€” ONE line of code, and your entire CSV file is now a working DataFrame!


Important Parameters of read_csv():

Parameter What it does Example
filepath Path/name of the CSV file (required!) "students.csv"
sep Character separating values (default is comma) sep=';' for semicolon files
header Which row is the column header header=0 (first row), header=None (no header)
names Give your own column names names=['ID','Name','Marks']
index_col Which column to use as row labels index_col='RollNo'
๐Ÿ’ก In Simple Words

header tells Pandas where the column names are (row 0, or None = there are none). names lets you give the column names. index_col picks a column to use instead of 0, 1, 2โ€ฆ as the row labels.


Case 1: CSV file WITHOUT a header row

1,Amit,85
2,Neha,90
3,Raj,78
# no_header_csv.py
import pandas as pd

df = pd.read_csv("data.csv", header=None,
                  names=['RollNo', 'Name', 'Marks'])
print(df)

Output:

   RollNo   Name  Marks
0       1   Amit     85
1       2   Neha     90
2       3    Raj     78

What happens if you forget header=None?

# forgot_header.py
df = pd.read_csv("data.csv")      # header=None missing!
print(df)

Output:

   1  Amit  85
0  2  Neha  90
1  3   Raj  78

The first student's data (1, Amit, 85) has become the column names, and only 2 rows of data are left.

โš  Forgetting header=None is a common mistake!

If your CSV has NO header row and you don't specify header=None, Pandas wrongly treats the FIRST DATA ROW as column names! You'd lose that row of actual data. Always check your CSV file first!


Case 2: Using a column as the row Index

# index_col_demo.py
import pandas as pd

df = pd.read_csv("students.csv", index_col='RollNo')
print(df)

Output:

         Name  Marks    City
RollNo
1        Amit     85   Delhi
2        Neha     90  Mumbai
3         Raj     78   Delhi
4       Priya     92    Pune

Instead of 0,1,2,3 as row labels, now RollNo itself becomes the index! Very useful for cleaner data access.


Case 3: Different separator (not comma)

Some files use semicolons ; or tabs \t instead of commas:

# custom_separator.py
import pandas as pd

df = pd.read_csv("data.txt", sep=';')     # Semicolon-separated file
df2 = pd.read_csv("data.tsv", sep='\t')   # Tab-separated file
๐Ÿ“‹ Board Exam Tip

"Write a statement to read a CSV file 'marks.csv' which has no header row, and assign column names as RollNo, Name, Marks." โ€” 2-mark question. Answer:

df = pd.read_csv("marks.csv", header=None, names=['RollNo', 'Name', 'Marks'])

4.2.2 Storing DataFrame's Data to CSV File ๐Ÿ“ค

The function df.to_csv() does the OPPOSITE โ€” it takes your DataFrame and saves it as a permanent CSV file!

# to_csv_basic.py
import pandas as pd

data = {
    'Name':  ['Amit', 'Neha', 'Raj'],
    'Marks': [85, 90, 78]
}
df = pd.DataFrame(data)

df.to_csv("output.csv")
print("File saved!")

The file output.csv will contain:

,Name,Marks
0,Amit,85
1,Neha,90
2,Raj,78

Notice the extra unnamed column with 0,1,2? That's the DataFrame's index being saved too โ€” usually we DON'T want that!


The index=False Fix โ€” MOST Important Parameter! โญ

# to_csv_clean.py
df.to_csv("output.csv", index=False)

Now the file contains (clean!):

Name,Marks
Amit,85
Neha,90
Raj,78
โš  Don't forget index=False!

Without it, your saved CSV file has an ugly extra column of row numbers (0,1,2...). ALWAYS add index=False unless you specifically need those numbers saved!


Important Parameters of to_csv():

Parameter What it does Example
path_or_buf File name to save as (required!) "result.csv"
sep Separator character to use sep=';'
index Whether to save row numbers index=False (recommended!)
header Whether to save column names header=True (default)
na_rep What text to show instead of NaN na_rep='Absent'

Handling Missing Values while Saving:

# na_rep_demo.py
import pandas as pd
import numpy as np

data = {
    'Name':  ['Amit', 'Neha', 'Raj'],
    'Marks': [85, np.nan, 78]      # Neha was absent!
}
df = pd.DataFrame(data)

df.to_csv("attendance.csv", index=False, na_rep='Absent')

File content:

Name,Marks
Amit,85.0
Neha,Absent
Raj,78.0

Instead of a blank or confusing "NaN" in the file, it now clearly says "Absent"!

Why 85.0 and not 85? As soon as a column contains a missing value (NaN), Pandas stores the whole column as decimal numbers, so the other marks are written as 85.0 and 78.0.

๐Ÿ“‹ Board Exam Tip

"Write code to save a DataFrame df to 'result.csv' without the index column." โ€” 2-mark question. Answer: df.to_csv("result.csv", index=False)


4.3 ๐Ÿ—„๏ธ Transferring Data between DataFrames and MySQL

Now let's connect our DataFrame directly to a MySQL database โ€” the more powerful, professional way to store data (used by real companies!).

What you need before starting:

# required_imports.py
import pandas as pd
import mysql.connector

If these libraries are not installed yet, install them once from the terminal (sqlalchemy is needed in Section 4.4):

pip install pandas mysql-connector-python sqlalchemy
๐Ÿ’ก In Simple Words โ€” Two Kinds of Connection

Reading from MySQL and writing to MySQL use two different "doors". Remember this small table and the rest of the chapter is easy:

Job Function What you pass as the connection
MySQL โ†’ DataFrame (read) pd.read_sql(query, conn) conn from mysql.connector.connect(...)
DataFrame โ†’ MySQL (write) df.to_sql(name, engine) engine from SQLAlchemy's create_engine(...)

An engine also works for reading โ€” pd.read_sql("SELECT * FROM Student", engine) โ€” but a mysql.connector connection does not work for to_sql().


4.3.1 Bringing Data from MySQL Database into a DataFrame ๐Ÿ“ฅ

The function pd.read_sql() runs an SQL query and puts the results directly into a DataFrame!

Step-by-step process:

graph LR
    S1["Step 1\nConnect to MySQL\nmysql.connector.connect()"]
    S2["Step 2\nWrite SQL Query\n'SELECT * FROM table'"]
    S3["Step 3\npd.read_sql(query, conn)"]
    S4["Step 4\nDataFrame Ready!"]

    S1 --> S2 --> S3 --> S4

    style S3 fill:#FF9800,color:#fff
    style S4 fill:#4CAF50,color:#fff
# read_sql_basic.py
import pandas as pd
import mysql.connector

# Step 1: Connect to MySQL
conn = mysql.connector.connect(
    host="localhost",
    user="root",
    password="yourpassword",
    database="SchoolDB"
)

# Step 2 & 3: Run query directly into a DataFrame
df = pd.read_sql("SELECT * FROM Student", conn)
print(df)

conn.close()

Output (assuming Student table has this data):

   RollNo   Name  Marks
0       1   Amit     85
1       2   Neha     90
2       3    Raj     78

Look how simple that is! Just ONE line (pd.read_sql()) does the job of connecting your database to a DataFrame โ€” no need to manually fetch rows and build the DataFrame yourself!

๐Ÿง  Seeing a "UserWarning" from Pandas? ๐Ÿง 

Newer versions of Pandas print a warning when read_sql() is given a mysql.connector connection, because they prefer a SQLAlchemy engine. It is only a warning โ€” the DataFrame is still created correctly. To avoid it, pass an engine instead (see Section 4.4).


Reading with a Filtered Query:

# read_sql_filtered.py
import pandas as pd
import mysql.connector

conn = mysql.connector.connect(
    host="localhost", user="root",
    password="yourpassword", database="SchoolDB"
)

# Only fetch students with Marks > 80:
df = pd.read_sql("SELECT * FROM Student WHERE Marks > 80", conn)
print(df)

conn.close()

read_sql() Parameters:

Parameter What it means
sql The SQL query string to run
con The connection object (from mysql.connector)
index_col Optional โ€” column to use as DataFrame's index
๐Ÿ“‹ Board Exam Tip

"Write code to fetch all records from the 'Student' table into a DataFrame." โ€” 3-mark question! Answer:

import pandas as pd
import mysql.connector

conn = mysql.connector.connect(host="localhost", user="root",
                                password="pass", database="SchoolDB")
df = pd.read_sql("SELECT * FROM Student", conn)
print(df)

4.3.2 Framing Flexible SQL Queries with User Data ๐ŸŽฏ

Instead of hardcoding values in your SQL, you can build the query using variables (like user input) โ€” making your program interactive!

# flexible_query.py
import pandas as pd
import mysql.connector

conn = mysql.connector.connect(
    host="localhost", user="root",
    password="yourpassword", database="SchoolDB"
)

# Take input from the user:
min_marks = int(input("Enter minimum marks to search: "))

# Build query using the variable (f-string):
query = f"SELECT * FROM Student WHERE Marks >= {min_marks}"

df = pd.read_sql(query, conn)
print(f"\nStudents scoring {min_marks} or above:")
print(df)

conn.close()

Sample Run:

Enter minimum marks to search: 80

Students scoring 80 or above:
   RollNo   Name  Marks
0       1   Amit     85
1       2   Neha     90

Another example โ€” Filter by City entered by user (for a Student table that also has a City column):

# flexible_query_city.py
city = input("Enter city name: ")
query = f"SELECT * FROM Student WHERE City = '{city}'"
df = pd.read_sql(query, conn)
print(df)

How the query is built โ€” step by step:

graph LR
    IN["โŒจ๏ธ User types\nDelhi"]
    VAR["city = 'Delhi'"]
    FS["The f-string puts\nthe value of city\ninto the query text"]
    OUT["SELECT * FROM Student\nWHERE City = 'Delhi'"]
    SQL["pd.read_sql()\nruns this query"]

    IN --> VAR --> FS --> OUT --> SQL

    style FS fill:#FFE0B2,stroke:#FF9800
    style OUT fill:#C8E6C9,stroke:#4CAF50

Numbers vs text inside the query:

  • A number goes in as it is: Marks >= {min_marks} becomes Marks >= 80.
  • Text must be wrapped in single quotes inside the string: City = '{city}' becomes City = 'Delhi'. Without the quotes, MySQL thinks Delhi is a column name and gives an error like Unknown column 'Delhi' in 'where clause'.
๐Ÿง  Why is this called "Flexible"? ๐Ÿง 

Because the SAME piece of code can answer DIFFERENT questions just by changing what the user types! Without user input, you'd need to rewrite the SQL query every single time you want different results. This makes real applications interactive!

โš  A Word of Caution โ€” SQL Injection!

Directly inserting user input into a query string (like above) can be risky in real-world applications โ€” a clever user could type something harmful instead of a normal value. The f-string method is the one usually taught in Class 12. In professional coding, parameterised queries (using %s) are safer!

๐Ÿ“‹ Board Exam Tip

"Write a program to accept a minimum marks value from the user and display matching student records from MySQL." โ€” 4-mark question! Key idea: Take input โ†’ Build query string with the variable โ†’ pd.read_sql(query, conn)


4.4 ๐Ÿ“ค Exporting a DataFrame's Data as a Table in MySQL Database

The function df.to_sql() does the reverse of read_sql() โ€” it takes your DataFrame and creates/updates a table in MySQL!

Important: For to_sql(), we typically use SQLAlchemy (a more powerful connection tool) instead of plain mysql.connector, because it handles data types automatically.

# to_sql_setup.py
import pandas as pd
from sqlalchemy import create_engine

# Create an "engine" โ€” SQLAlchemy's special connection object:
engine = create_engine("mysql+mysqlconnector://root:yourpassword@localhost/SchoolDB")

Breaking down the connection string "mysql+mysqlconnector://root:yourpassword@localhost/SchoolDB":

Part Meaning Comes after
mysql+mysqlconnector:// Use MySQL, through the mysql-connector driver โ€” (always the same)
root Your MySQL username //
yourpassword Your MySQL password :
localhost The computer where MySQL runs (your own computer) @
SchoolDB The database to open /

Read it like a sentence: "use MySQL through mysql-connector, log in as root with password yourpassword, on localhost, and open SchoolDB".


Complete Example โ€” Exporting a DataFrame to MySQL:

# to_sql_complete.py
import pandas as pd
from sqlalchemy import create_engine

# Step 1: Create the DataFrame
data = {
    'RollNo': [5, 6, 7],
    'Name':   ['Sita', 'Karan', 'Meera'],
    'Marks':  [88, 72, 95]
}
df = pd.DataFrame(data)

# Step 2: Create connection engine
engine = create_engine("mysql+mysqlconnector://root:yourpassword@localhost/SchoolDB")

# Step 3: Export DataFrame to MySQL table
df.to_sql('Student', engine, if_exists='append', index=False)

print("Data exported to MySQL successfully!")

to_sql() Parameters:

Parameter What it means Common Values
name Name of the table to write to 'Student'
con The connection engine SQLAlchemy engine
if_exists What to do if the table already exists 'fail', 'replace', 'append'
index Whether to include DataFrame index as a column index=False (recommended!)

Understanding if_exists โš ๏ธ

โŒ

if_exists='fail'

Stops with an error if table already exists

Default โ€” safest but least useful
๐Ÿ’ฃ

if_exists='replace'

DELETES the old table completely, creates a NEW one

Use carefully โ€” you LOSE old data!
โœ…

if_exists='append'

ADDS new rows to the existing table (keeps old data)

Most commonly used โ€” safest for adding data!
graph TD
    START["df.to_sql('Student', engine, if_exists=?)"]
    FAIL["'fail'\nโŒ ERROR if\ntable exists"]
    REPLACE["'replace'\n๐Ÿ’ฃ Deletes old table,\nmakes new one"]
    APPEND["'append'\nโœ… Adds new rows,\nkeeps old data"]

    START --> FAIL
    START --> REPLACE
    START --> APPEND

    style FAIL fill:#9E9E9E,color:#fff
    style REPLACE fill:#F44336,color:#fff
    style APPEND fill:#4CAF50,color:#fff
โš  if_exists='replace' is DANGEROUS!

This DELETES the entire existing table (including all old data!) and creates a fresh one with only your new DataFrame's data. In almost all real situations, you want 'append' instead โ€” which safely ADDS your new rows without losing anything!

๐Ÿ“‹ Board Exam Tip

"Write code to export a DataFrame df to a MySQL table named 'Result' without deleting existing data." โ€” 3-mark question! Answer:

from sqlalchemy import create_engine
engine = create_engine("mysql+mysqlconnector://root:pass@localhost/SchoolDB")
df.to_sql('Result', engine, if_exists='append', index=False)

Key point: use if_exists='append' to NOT delete existing data!


๐Ÿ“ Complete Data Flow โ€” The Big Picture

graph TD
    CSV["๐Ÿ“„ CSV File"]
    DF["๐Ÿผ Pandas DataFrame\n(In Python Memory)"]
    SQL["๐Ÿ—„๏ธ MySQL Database Table"]

    CSV -->|"pd.read_csv()"| DF
    DF -->|"df.to_csv()"| CSV
    SQL -->|"pd.read_sql()"| DF
    DF -->|"df.to_sql()"| SQL

    style DF fill:#FF9800,color:#fff
    style CSV fill:#4CAF50,color:#fff
    style SQL fill:#2196F3,color:#fff

The Four Key Functions โ€” Master These!

Function Direction Purpose
pd.read_csv() CSV โ†’ DataFrame Load data FROM a CSV file
df.to_csv() DataFrame โ†’ CSV Save data TO a CSV file
pd.read_sql() MySQL โ†’ DataFrame Load data FROM a MySQL table
df.to_sql() DataFrame โ†’ MySQL Save data TO a MySQL table

๐Ÿ“Š CSV vs MySQL โ€” When to Use Which?

Feature CSV File MySQL Database
Setup Very simple โ€” just a text file Needs a server running
Speed for small data Fast Slightly slower (network/connection overhead)
Multiple users at once โŒ Difficult (file conflicts) โœ… Designed for this
Filtering large data Loads everything, then filters in Python Filters BEFORE loading (WHERE clause) โ€” much faster!
Best for Quick exports, backups, small projects Real applications, large data, multi-user systems
๐Ÿง  Why filter in SQL, not in Python? ๐Ÿง 

pd.read_sql("SELECT * FROM Student WHERE Marks > 80", conn) only fetches the matching rows from the database โ€” saving memory and time. Compare this to pd.read_csv() which loads the ENTIRE file first, then you filter afterwards in Python. For huge datasets, SQL filtering is much more efficient!


โš ๏ธ Common Errors and Misconceptions

Mistake What Goes Wrong Fix
โŒ Forgetting index=False in to_csv() Extra unnamed column of row numbers in the file โœ… Always add index=False
โŒ Not using header=None for header-less CSV First data row becomes column names, data is lost โœ… Use header=None, names=[...]
โŒ FileNotFoundError Wrong file name/path, or file in a different folder โœ… Check spelling and file location
โŒ Using if_exists='replace' casually Deletes ALL existing data in that table! โœ… Use 'append' unless you truly want to reset the table
โŒ Forgetting to import mysql.connector NameError: name not defined โœ… Always import mysql.connector at the top
โŒ Wrong MySQL password/host in connection InterfaceError or Access Denied โœ… Double-check credentials
โŒ Not closing the MySQL connection Wastes server resources โœ… Always call conn.close() at the end
โŒ Passing a mysql.connector connection to to_sql() Pandas cannot write through it and raises an error โœ… Create an engine with create_engine(...) and pass that
โŒ Text without quotes in an f-string query, e.g. City = {city} Error like Unknown column 'Delhi' โœ… Write City = '{city}'

๐ŸŽฏ Sample Board Exam Questions

Q1: Very Short Answer [1 mark each]

a) Which function is used to read a CSV file into a DataFrame? โ†’ pd.read_csv()

b) Which parameter of to_csv() prevents the extra index column from being saved? โ†’ index=False

c) What does if_exists='append' do in to_sql()? โ†’ Adds new rows to the existing table without deleting old data.

d) What does CSV stand for? โ†’ Comma Separated Values

e) Which function reads data from a MySQL table into a DataFrame? โ†’ pd.read_sql()


Q2: Short Answer [2 marks]

Q: Differentiate between if_exists='replace' and if_exists='append' in to_sql().

if_exists='replace' deletes the existing table completely and creates a brand new one containing only the current DataFrame's data โ€” all previous data is lost. if_exists='append' adds the new DataFrame's rows to the existing table, keeping all the previous data intact. This is the safer and more commonly used option.


Q3: Program Writing [3 marks]

Q: Write a program to read data from "marks.csv" (with columns RollNo, Name, Marks) and display only students scoring above 75.

import pandas as pd

df = pd.read_csv("marks.csv")
print("Students scoring above 75:")
print(df[df['Marks'] > 75])

Q4: Program Writing [4 marks]

Q: Write a program to create a DataFrame of 3 students and save it to "students.csv" without the index column. Also handle any missing marks by writing "NA".

import pandas as pd
import numpy as np

data = {
    'Name':  ['Aman', 'Kavya', 'Rohan'],
    'Marks': [88, np.nan, 92]
}
df = pd.DataFrame(data)

df.to_csv("students.csv", index=False, na_rep='NA')
print("File saved successfully!")

Q5: Program Writing [4 marks]

Q: Write a program that connects to a MySQL database 'SchoolDB', reads data from the 'Student' table where Marks are greater than a user-given value, and displays it.

import pandas as pd
import mysql.connector

conn = mysql.connector.connect(
    host="localhost",
    user="root",
    password="yourpassword",
    database="SchoolDB"
)

marks = int(input("Enter minimum marks: "))
query = f"SELECT * FROM Student WHERE Marks > {marks}"

df = pd.read_sql(query, conn)
print(df)

conn.close()

โœ๏ธ Practice Problems

  1. Write code to read "products.csv" and display the top 5 rows using head().

  2. Create a DataFrame with 4 employees (Name, Department, Salary) and save it as "employees.csv" without the index column.

  3. A CSV file "raw_data.csv" has no header row and contains ID, Item, Price. Write code to read it correctly with proper column names.

  4. Write a program to read data from a MySQL table 'Products' where Price is less than a value entered by the user.

  5. Write code to export a DataFrame df to a MySQL table called 'Inventory', replacing any existing table completely.

  6. Explain the difference between read_csv() and read_sql(). When would you prefer one over the other?

  7. Write a program that reads "attendance.csv", replaces missing values (NaN) with the text "Absent" while displaying, and saves an updated version.

  8. Create a DataFrame and append its data safely to an existing MySQL table called 'Sales', ensuring old records are not deleted.

  9. What happens if you use to_csv() without the index=False parameter? Show the difference with and without it using a short example.

  10. Write a flexible program that asks the user for a city name and displays all matching student records from a MySQL 'Student' table.

Take the Chapter 04 Quiz Custom Quiz
Solved Board Questions

Practice real board exam questions for this chapter.

View Solved Board Questions
Learning Support

Need Help With This Chapter?

Save key topics for exam revision, ask questions to teachers, or submit content corrections.

Verified Doubts & Teacher Answers

Chapter 04 Quiz