Python and SQL for Manufacturing: Hands-On Training¶
Demo Notebook 4: Capstone — SQL + Python + Charts Mini-Report¶
Author: Prakash Ukhalkar
Role: Assistant Professor (MCA) | Researcher in Data Science and Machine Learning
Notebook Scope: Bring together everything from Notebooks 1–3 — connect to SQLite, query with SQL, visualize with Matplotlib, and export a summary report to CSV.
This capstone notebook follows a real-world mini-pipeline:
SQLite DB → SQL Query → Python → Chart → CSV Report
By the end of this notebook you will be able to:
- Query and summarise data across multiple tables
- Identify the top earners per department
- Build a combined summary chart
- Export a report to a CSV file
Prerequisite: Complete
day1_emp_dept.ipynb,day2_querying.ipynb, andday3_visualization.ipynbfirst.
Step 1 — Import libraries and connect¶
import sqlite3
import csv
import matplotlib.pyplot as plt
conn = sqlite3.connect('company.db')
cursor = conn.cursor()
print('Connected to company.db')
Connected to company.db
Step 2 — Full employee roster (SQL + JOIN)¶
Pull every employee along with their department name and location — our master data view.
roster = cursor.execute('''
SELECT e.empno, e.ename, e.job, e.sal, d.dname, d.loc
FROM emp AS e
JOIN dept AS d ON e.deptno = d.deptno
ORDER BY d.dname, e.sal DESC
''').fetchall()
print(f'Total employees: {len(roster)}')
print()
print(f'{"Emp#":<6} {"Name":<8} {"Job":<11} {"Salary":>7} {"Dept":<12} {"Location"}')
print('-' * 60)
for r in roster:
print(f'{r[0]:<6} {r[1]:<8} {r[2]:<11} {r[3]:>7} {r[4]:<12} {r[5]}')
Total employees: 14 Emp# Name Job Salary Dept Location ------------------------------------------------------------ 7839 KING PRESIDENT 5000.0 ACCOUNTING NEW YORK 7782 CLARK MANAGER 2450.0 ACCOUNTING NEW YORK 7934 MILLER CLERK 1300.0 ACCOUNTING NEW YORK 7788 SCOTT ANALYST 3000.0 RESEARCH DALLAS 7902 FORD ANALYST 3000.0 RESEARCH DALLAS 7566 JONES MANAGER 2975.0 RESEARCH DALLAS 7876 ADAMS CLERK 1100.0 RESEARCH DALLAS 7369 SMITH CLERK 900.0 RESEARCH DALLAS 7698 BLAKE MANAGER 2850.0 SALES CHICAGO 7499 ALLEN SALESMAN 1600.0 SALES CHICAGO 7844 TURNER SALESMAN 1500.0 SALES CHICAGO 7521 WARD SALESMAN 1250.0 SALES CHICAGO 7654 MARTIN SALESMAN 1250.0 SALES CHICAGO 7900 JAMES CLERK 950.0 SALES CHICAGO
Step 3 — Department summary (GROUP BY + aggregates)¶
For each department: headcount, total salary, and average salary.
summary = cursor.execute('''
SELECT d.dname,
COUNT(e.empno) AS headcount,
SUM(e.sal) AS total_sal,
AVG(e.sal) AS avg_sal,
MAX(e.sal) AS top_sal
FROM emp AS e
JOIN dept AS d ON e.deptno = d.deptno
GROUP BY d.dname
ORDER BY d.dname
''').fetchall()
print(f'{"Department":<14} {"Headcount":>10} {"Total Sal":>10} {"Avg Sal":>9} {"Top Sal":>9}')
print('-' * 58)
for r in summary:
print(f'{r[0]:<14} {r[1]:>10} {r[2]:>10.0f} {r[3]:>9.2f} {r[4]:>9.0f}')
Department Headcount Total Sal Avg Sal Top Sal ---------------------------------------------------------- ACCOUNTING 3 8750 2916.67 5000 RESEARCH 5 10975 2195.00 3000 SALES 6 9400 1566.67 2850
Step 4 — Top earner per department (Subquery)¶
For each department, find the employee with the highest salary.
top_earners = cursor.execute('''
SELECT d.dname, e.ename, e.job, e.sal
FROM emp AS e
JOIN dept AS d ON e.deptno = d.deptno
WHERE e.sal = (
SELECT MAX(e2.sal)
FROM emp AS e2
WHERE e2.deptno = e.deptno
)
ORDER BY d.dname
''').fetchall()
print('Top earner per department:')
print(f'{"Department":<14} {"Employee":<8} {"Job":<11} {"Salary":>7}')
print('-' * 44)
for r in top_earners:
print(f'{r[0]:<14} {r[1]:<8} {r[2]:<11} {r[3]:>7}')
Top earner per department: Department Employee Job Salary -------------------------------------------- ACCOUNTING KING PRESIDENT 5000.0 RESEARCH SCOTT ANALYST 3000.0 RESEARCH FORD ANALYST 3000.0 SALES BLAKE MANAGER 2850.0
Step 5 — Employees above the company average salary¶
A quick check on who earns above the mean.
above_avg = cursor.execute('''
SELECT ename, job, sal
FROM emp
WHERE sal > (SELECT AVG(sal) FROM emp)
ORDER BY sal DESC
''').fetchall()
company_avg = cursor.execute('SELECT AVG(sal) FROM emp').fetchone()[0]
print(f'Company average salary: {company_avg:.2f}')
print()
print('Employees above average:')
for r in above_avg:
print(f' {r[0]:<8} {r[1]:<11} {r[2]}')
Company average salary: 2080.36 Employees above average: KING PRESIDENT 5000.0 SCOTT ANALYST 3000.0 FORD ANALYST 3000.0 JONES MANAGER 2975.0 BLAKE MANAGER 2850.0 CLARK MANAGER 2450.0
Step 6 — Combined chart: Headcount and Average Salary side by side¶
Two subplots in one figure — a common pattern in management reports.
depts = [r[0] for r in summary]
headcount = [r[1] for r in summary]
avg_sal = [r[3] for r in summary]
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4))
# Left: headcount
ax1.bar(depts, headcount, color='steelblue')
ax1.set_title('Headcount by Department')
ax1.set_xlabel('Department')
ax1.set_ylabel('Number of Employees')
# Right: average salary
ax2.bar(depts, avg_sal, color='darkorange')
ax2.set_title('Average Salary by Department')
ax2.set_xlabel('Department')
ax2.set_ylabel('Average Salary')
plt.suptitle('Department Overview', fontsize=13, fontweight='bold')
plt.tight_layout()
plt.show()
Step 7 — Export the department summary to CSV¶
Saving results to a CSV file is useful for sharing reports or loading into Excel.
csv_file = 'department_summary.csv'
with open(csv_file, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['Department', 'Headcount', 'Total Salary', 'Avg Salary', 'Top Salary'])
for r in summary:
writer.writerow([r[0], r[1], round(r[2], 2), round(r[3], 2), round(r[4], 2)])
print(f'Saved to {csv_file}')
Saved to department_summary.csv
# Read the file back to verify
with open(csv_file) as f:
for line in f:
print(line.rstrip())
Department,Headcount,Total Salary,Avg Salary,Top Salary ACCOUNTING,3,8750.0,2916.67,5000.0 RESEARCH,5,10975.0,2195.0,3000.0 SALES,6,9400.0,1566.67,2850.0
Step 8 — Close the connection¶
conn.close()
print('Done! Report saved to department_summary.csv')
Done! Report saved to department_summary.csv
Summary — Full Pipeline¶
| Step | What happened |
|---|---|
| Connect | sqlite3.connect('company.db') |
| Full roster | SELECT ... JOIN dept |
| Department summary | GROUP BY with COUNT, SUM, AVG, MAX |
| Top earner per dept | Correlated subquery with MAX |
| Above-average filter | WHERE sal > (SELECT AVG ...) |
| Combined chart | plt.subplots(1, 2) with two bar charts |
| Export | csv.writer to department_summary.csv |
Previous: day3_visualization.ipynb — bar, pie, line, and scatter charts.
About This Material¶
| Author | Prakash Ukhalkar |
| Role | Assistant Professor (MCA) · Researcher in Data Science and Machine Learning |
| GitHub | @prakash-ukhalkar |
| Repository | mfg-python-sql-training |
| License | MIT |
Provided for educational use in manufacturing analytics training programmes.
For questions, corrections, or contributions, open an issue or pull request on GitHub.