LambdaLabTM
Computer Science · Class 12 Project · Subject Code 083
Sample ProjectPython + MySQL⏱️ 12 min read

Hostel Mess Bill Splitter

Divide a month's mess spending by the meals each member actually ate.

1Introduction: the problem it solves

A hostel mess buys vegetables, rice and gas all month, and at month end the bill is split equally. That is unfair to whoever went home for a week, and everybody knows it, which is why the argument happens every month.

Splitting by meals eaten is obviously fairer and nobody does it by hand, because it means totalling a register of daily meal counts. That is exactly what a database is for.

who would use it

A hostel mess, a PG kitchen, a shared flat, or a school trip's food fund.

Why it is worth computerising

A mess bill divided equally is simple to calculate and unfair to anybody who was away, and everyone living there knows it. The argument at the end of every month is not really about money; it is about the fact that nobody has the figures to settle it.

The figures exist — the daily meal register has them — but totalling a month of them by hand and dividing the bazaar spending in proportion is precisely the work nobody volunteers for. A database does the totalling, and the result has a property the equal split never had: the shares add back exactly to what was spent, and every member can check their own count against the register.

Objectives

  1. To record what the mess actually spends, item by item, through the month
  2. To record how many meals each member ate on each day
  3. To work out a rate per meal rather than a rate per person
  4. To give every member a share proportional to what they ate
  5. To ensure the shares add back exactly to what was spent

2How the job is done today

Before writing anything it is worth asking how the work is handled at present, and why each of those answers falls short. These were examined:

Equal division at month end

Simple, and the reason the argument happens. Anyone who was away for a week pays for meals they did not eat.

Mess management apps

They exist, and they want the whole mess on smartphones with an account each. A three-person hostel kitchen will not do that.

Register of daily meals

The right data, collected by hand. The totalling and the division are exactly the work nobody wants at month end.

3Functionalities

  • Three tables: members, monthly expenses, and a daily meal register
  • Records each member's meals for each day
  • Totals the month's spending with SUM()
  • Works out a rate per meal instead of a rate per person
  • Gives each member a share proportional to what they ate
  • The shares add back to the total exactly, which is what stops the argument

The functions that provide them

FunctionArgumentsWhat it does
record_meals()member_id, day, mealsRecord how many meals one member ate on one day.
month_bill()monthTotal the month's bazaar spending and divide it by meals eaten.

4Technical details

LanguagePython 3
StorageMySQL, through mysql-connector-python
Modules used
  • mysql.connector — the database connection
  • MySQL — SUM(), GROUP BY, a JOIN, and LIKE for matching a month

5How the data is stored

Meals are stored per member per day rather than as a monthly total. It is more rows, and it is worth it: a disputed bill can be checked against a single day, and a member who joins mid-month needs no special handling.

Table: members

FieldTypeDescription
member_idINT (primary key, auto)Unique number for each member of the mess
nameVARCHAR(30) (required)Member's name
roomVARCHAR(6)Room number in the hostel

Table: expenses

FieldTypeDescription
expense_idINT (primary key, auto)Unique number for each purchase
monthVARCHAR(7)Month the spending belongs to, as YYYY-MM
itemVARCHAR(30)What was bought
amountDECIMAL(10,2)What it cost

Table: meals

FieldTypeDescription
entry_idINT (primary key, auto)Unique number for each day's entry
member_idINTWhich member — refers to members
meal_dateDATEThe day
countINTHow many meals that member ate that day

Sample rows in members

nameroom
Ananya SenB-12
Rohit DasB-14
Meera RaiC-03

Sample rows in expenses

monthitemamount
2026-08Vegetables4200.00
2026-08Rice and atta5100.00
2026-08Milk and eggs2700.00
2026-08Gas cylinder1150.00

Sample rows in meals

member_idmeal_datecount
12026-08-012
22026-08-012
32026-08-011
12026-08-022
22026-08-020
32026-08-022

6How it works, step by step

1
Record

record_meals() INSERTs one row per member per day.

2
Total

SUM(amount) over the month's expenses gives what the mess actually spent.

3
Rate

Total spending divided by total meals is the cost of one meal.

4
Split

A JOIN with GROUP BY gives each member's meal count, and count x rate is their share.

7Source code

mess.py
# ---------------------------------------------------------------------------
# mess.py
#
# Splits a hostel mess bill by the meals each member actually ate, using
# Python with MySQL.
#
# Three tables: the members, what the mess spent, and a register of meals eaten
# per member per day. Storing meals daily rather than as a monthly total is
# what lets a disputed figure be checked against a single day.
# ---------------------------------------------------------------------------

import mysql.connector

db = mysql.connector.connect(host="localhost", user="root",
                             passwd="mess", database="lambdalab_mess")
cur = db.cursor()


def record_meals(member_id, day, meals):
    """Record how many meals one member ate on one day."""
    cur.execute("INSERT INTO meals (member_id, meal_date, count) VALUES (%s, %s, %s)",
                (member_id, day, meals))
    db.commit()


def month_bill(month):
    """Total the month's bazaar spending and divide it by meals eaten."""
    # SUM() adds a whole column inside the database and returns one number, so
    # the rows never have to travel into Python at all.
    cur.execute("SELECT SUM(amount) FROM expenses WHERE month = %s", (month,))
    total = cur.fetchone()[0]              # [0] because the row holds one value

    # LIKE '2026-08%' matches every date inside that month. A proper date range
    # would be better, and is listed under future scope.
    cur.execute("SELECT SUM(count) FROM meals WHERE meal_date LIKE %s", (month + "%",))
    all_meals = cur.fetchone()[0]

    # The whole idea of the program in one line: a rate per MEAL, not per head.
    rate = total / all_meals

    print("LAMBDALAB HOSTEL MESS — {}".format(month))
    print("Bazaar spending : Rs {:.2f}".format(total))
    print("Meals eaten     : {}".format(all_meals))
    print("Rate per meal   : Rs {:.2f}\n".format(rate))

    # GROUP BY gives one row per member with their own total, and the JOIN
    # brings in the name to go with the id.
    cur.execute("SELECT m.name, SUM(t.count) FROM meals t"
                " JOIN members m ON t.member_id = m.member_id"
                " WHERE t.meal_date LIKE %s GROUP BY m.name ORDER BY m.name", (month + "%",))

    print("{:<18}{:>8}{:>12}".format("MEMBER", "MEALS", "SHARE"))

    # Because every meal is charged at the same rate, the shares add back
    # exactly to what was spent — which is what settles the argument.
    for name, meals in cur.fetchall():
        print("{:<18}{:>8}{:>12.2f}".format(name, meals, meals * rate))


# --- the program itself ----------------------------------------------------

month_bill("2026-08")

db.close()
schema.sql
CREATE DATABASE IF NOT EXISTS lambdalab_mess;
USE lambdalab_mess;

CREATE TABLE members (
    member_id INT PRIMARY KEY AUTO_INCREMENT,
    name      VARCHAR(30) NOT NULL,
    room      VARCHAR(6)
);

CREATE TABLE expenses (
    expense_id INT PRIMARY KEY AUTO_INCREMENT,
    month      VARCHAR(7),
    item       VARCHAR(30),
    amount     DECIMAL(10,2)
);

CREATE TABLE meals (
    entry_id  INT PRIMARY KEY AUTO_INCREMENT,
    member_id INT,
    meal_date DATE,
    count     INT DEFAULT 0,
    FOREIGN KEY (member_id) REFERENCES members(member_id)
);

INSERT INTO members (name, room) VALUES
    ('Ananya Sen', 'B-12'), ('Rohit Das', 'B-14'), ('Meera Rai', 'C-03');

INSERT INTO expenses (month, item, amount) VALUES
    ('2026-08', 'Vegetables',    4200.00),
    ('2026-08', 'Rice and atta', 5100.00),
    ('2026-08', 'Milk and eggs', 2700.00),
    ('2026-08', 'Gas cylinder',  1150.00);

INSERT INTO meals (member_id, meal_date, count) VALUES
    (1, '2026-08-01', 2), (2, '2026-08-01', 2), (3, '2026-08-01', 1),
    (1, '2026-08-02', 2), (2, '2026-08-02', 0), (3, '2026-08-02', 2),
    (1, '2026-08-03', 2), (2, '2026-08-03', 2), (3, '2026-08-03', 2);
⬇️ Take it with you

The full report as a PDF — cover page, certificate, index, code, output, future scope and references, ready to print and fill in. Or the code on its own as a zip.

or one file:

8Sample output

This is a real run, not a mock-up — the transcript below is what the program actually printed.

Command Prompt
C:\LambdaLab\Projects\Mess-Bill> python mess.py
LAMBDALAB HOSTEL MESS — 2026-08
Bazaar spending : Rs 13150.00
Meals eaten     : 15
Rate per meal   : Rs 876.67

MEMBER               MEALS       SHARE
Ananya Sen               6     5260.00
Meera Rai                5     4383.33
Rohit Das                4     3506.67
Note
Before this will run, import schema.sql into MySQL and change the user and password in the connect() call to your own. The output above is what the queries return against the sample rows in that schema.

9Testing

Every case below was actually run and the result recorded as it appeared — including the ones expected to fail.

Test caseExpectedActual
Total spending for the monthRs 13150.00Rs 13150.00
Total meals eaten1515 meals
Rate per meal13150 / 15 = Rs 876.67Rs 876.67
Shares add back to the totalThe three shares sum to 13150.00Rs 13150.00
A member who ate nothing that monthShare of zero, no errorRs 0.00

Two kinds of case are in there on purpose. The boundary cases test the edge of a rule, where a program is most often wrong by one. The failure cases check that it refuses cleanly and says why, instead of quietly producing a wrong answer.

10Advantages

Set against the ways the job is done today:

  • The split is proportional to what each member actually ate
  • The shares add back exactly to what was spent, which ends the argument
  • A disputed figure can be checked against a single day's entry
  • A member joining mid-month needs no special treatment
  • The rate per meal is a figure everybody can see and question

11Future scope

What this version does not do

A report should be honest about its own limits, and each of these is the reason for one of the additions below:

  • Guest meals are not charged to the member who invited them
  • Payments received are not recorded, so dues are not tracked
  • The month is matched with LIKE on a date column, which a proper date range would do better
  • The leftover paisa in the division is not assigned to anybody

Proposed enhancements

This is also where you make the project yours. Pick one or two of these, or something nobody here thought of:

  • A guest meal charged to the member who invited them
  • Print each member's slip separately
  • Chart the rate per meal across months, which shows inflation plainly
  • Let members mark themselves absent in advance so the cook can buy less
  • Track who has paid and what is outstanding

12What you may have to teach yourself

CBSE expects some self-learning in a project, and says so. For this one, that means:

  • SUM() and GROUP BY together, which is the heart of every report query
  • LIKE '2026-08%' for matching a month, and why a DATE column would let you do better
  • Rounding: whose share carries the leftover paisa? Decide it and say so in the report

13Conclusion

The month's bill is divided by meals eaten rather than by heads counted, and the shares add back exactly to what was spent.

The argument this was written to settle was never about arithmetic; it was about not having the figures. Collecting meals daily, one row at a time, is what made the fair split possible at all.

14References

Every report needs a bibliography. This one used:

  • Computer Science with Python, Class XII — the NCERT / CBSE prescribed textbook, for the chapters on database concepts, SQL and interfacing Python with a database
  • Computer Science with Python, Class XI — for functions, lists, dictionaries and string handling
  • Python 3 documentation — https://docs.python.org/3/
  • MySQL 8.0 Reference Manual and the Connector/Python Developer Guide — https://dev.mysql.com/doc/
  • CBSE Senior School Curriculum, Computer Science (Subject Code 083) — the project guidelines this report follows
  • LambdaLab — https://www.lambdalab.in
Key Takeaway
The PDF above is the whole report. Cover page, certificate, acknowledgement, index, everything on this page, and the references — in the order CBSE marks them, ready to print. The cover page, certificate and acknowledgement arrive with blank rules where names go, because a certificate with somebody else's name printed on it is not a template. Fill those in, get the certificate signed, and replace the problem with one you have looked into yourself.