DAY 08 · PRACTICE

Python · Java · JavaScript · SQL

📦 Topics: Generators · Matrices · Stack · Compression · Inheritance · SQL LIKE/IN/CASE ⏱ Est: 3–4 hrs total 🎯 Difficulty: 2.5 / 5
01
Fibonacci Generator 🌀
GENERATORYIELDEASY~20 min
📖 Scenario
Spotify's "endless shuffle", YouTube's infinite scroll, and any live data feed uses the idea of something that produces values one at a time, on demand. In Python this is called a generator — a function that uses yield instead of return. It pauses after each value and resumes exactly where it left off the next time you ask.
🧠 yield vs return return — exits the function completely. Done forever.
yield — pauses the function, hands back one value, then waits.
Next time you call next() on it, it continues from the line after yield.
A generator never holds the whole list in memory — it makes one value at a time.
Starter Code
def fibonacci(limit): a, b = 0, 1 while a <= limit: yield a # pause here, give back 'a' a, b = b, a + b # resume here on next call # Write your answers below
Your Tasks
  • Collect all values from the generator up to 50 into a list and print them. Use a built-in Python function to convert the generator's sequence into a full list.
  • Use a loop to iterate through the generator up to 50, but only print the even Fibonacci numbers and calculate their total sum. A generator works directly in a loop — no need to convert it to a list first.
  • Create a new generator instance and manually extract only the first 8 numbers. Assign the generator to a variable and use a built-in function to pull the next item sequentially.
  • What happens if you try to extract a value after the generator has hit its limit? Try it and observe the error.
Expected OutputAll up to 50: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] Even fibs: [0, 2, 8, 34] → Sum: 44 First 8: [0, 1, 1, 2, 3, 5, 8, 13] After exhaustion: StopIteration error
💡 One Hint Trace the first few steps by hand: write down the values of 'a' and 'b', and see how they shift after each yield. What happens to a generator when it runs out of items?
02
Matrix Operations 🔢
2D LISTNESTED LOOPSEASY~25 min
📖 Scenario
Matrices are used in game development (rotation/movement), image processing (each pixel is a cell), and machine learning (neural network weights). A matrix in Python is just a list of lists. You access any cell with matrix[row][col]. Today you'll transpose it, sum rows and columns, and find the diagonal.
Starter Code
matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ] # matrix[0][0]=1 matrix[0][1]=2 matrix[1][0]=4 etc. # Write your code below
Your Tasks
  • Create a new grid that represents the transpose — where rows become columns. Use nested loops to swap the row and column indices when filling the new grid.
  • Print the total sum of each row. Consider using Python's built-in sum utility inside your loop.
  • Print the total sum of each column. You will need to loop over the column indices first, then travel down the rows.
  • Print the diagonal sum. Find the pattern for cells that go from the top-left to the bottom-right.
Expected OutputTranspose: [1, 4, 7] [2, 5, 8] [3, 6, 9] Row sums: [6, 15, 24] Column sums: [12, 15, 18] Diagonal sum: 15
💡 One Hint For the transpose, think about creating an empty grid first, then swapping the row and column indices. For the diagonal, do you really need nested loops if the row and column indices are always identical?
03
Balanced Brackets Checker 🔍
STACKSTRINGEASY~25 min
📖 Scenario
Every code editor — VS Code, PyCharm, IntelliJ — uses this exact algorithm to show you a red underline when your brackets don't match. ([{}]) is valid. ([)] is not. The trick is using a Stack — a list where you only add and remove from the top (like a stack of plates). Push opening brackets on, pop when you see a closing one, check they match.
🧠 Stack = LIFO LIFO = Last In, First Out. Whatever you pushed last is the first thing you pop.
In Python a regular list works as a stack:
stack.append(x) → push (add to top)
stack.pop() → pop (remove from top)
stack[-1] → peek (look at top without removing)
Starter Code
def is_balanced(s): stack = [] pairs = {')': '(', ']': '[', '}': '{'} for ch in s: if ch in '([{': pass # push ch onto the stack elif ch in ')]}': pass # if stack empty or top doesn't match → False, else pop return # True only if stack is empty at the end tests = ["(())", "([{}])", "(()", "([)]", ""] for t in tests: print(f'"{t}" → {is_balanced(t)}')
Your Tasks
  • Fill the first TODO: Add the character to your stack when it is an opening bracket.
  • Fill the second TODO: When encountering a closing bracket, check the most recent item added to your stack. If it doesn't match the required opening bracket (or if the stack is already empty), return False. Otherwise, remove the top item.
  • Fill the final return: The function should only return True if there are no leftover brackets in the stack.
  • Trace "([)]" step by step on paper to understand exactly which line causes it to return False.
Expected Output"(())" → True "([{}])" → True "(()" → False "([)]" → False "" → True
💡 One Hint Trace the string step by step. When you encounter a closing bracket, what should be at the very top of your stack for it to be valid? Make sure to check if the stack is empty before peeking!
04
String Compression 🗜️
STRINGLOOPSEASY~20 min
📖 Scenario
ZIP files, PNG images, and WhatsApp message compression all use some form of run-length encoding — a basic compression trick where you replace repeated characters with the character and a count. "aabcccdddd" becomes "a2bc3d4". If the compressed version is not shorter, keep the original.
Starter Code
def compress(s): if not s: return "" result = "" # TODO: Iterate through 's', count consecutive characters # TODO: Append the character and its count (if > 1) to 'result' # TODO: Don't forget to handle the final sequence of characters! return result # Update this to return the shorter of the two for word in ["aabcccdddd", "abcd", "aaabba", "aaaaaa"]: print(f'"{word}" → "{compress(word)}"')
Your Tasks
  • Set up a loop to iterate through the string and count consecutive repeating characters.
  • When a new character is encountered, append the previous character and its count (if > 1) to your result string. Then reset your counter.
  • After the loop ends, apply the same logic to handle the final sequence of characters that the loop didn't trigger an append for.
  • Ensure your function returns the compressed string only if it is strictly shorter than the original string.
Expected Output"aabcccdddd" → "a2bc3d4" "abcd" → "abcd" "aaabba" → "a3b2a" "aaaaaa" → "a6"
💡 One Hint Think about what happens to the very last sequence of characters. Does the loop ever reach a point where it realizes the last sequence has ended? Make sure to handle the final sequence outside the loop!
05
Shape Hierarchy — Inheritance 🔷
OOPINHERITANCEMEDIUM~30 min
📖 Scenario
A drawing app needs to handle circles, rectangles, and triangles. They all share common behaviour — every shape has a colour and a way to describe itself — but each calculates area differently. This is the core use case for inheritance: a parent class defines shared behaviour, child classes override what's different.
Starter Code
import math class Shape: def __init__(self, color): self.color = color def area(self): return 0 # subclasses will override this def describe(self): return f"{self.color} {self.__class__.__name__} with area {self.area():.2f}" class Circle(Shape): def __init__(self, color, radius): pass # call super().__init__(color), store radius def area(self): pass # math.pi * radius squared class Rectangle(Shape): def __init__(self, color, width, height): pass def area(self): pass # width * height class Triangle(Shape): def __init__(self, color, base, height): pass def area(self): pass # 0.5 * base * height shapes = [ Circle("Red", 7), Rectangle("Blue", 5, 8), Triangle("Green", 6, 10), ] for s in shapes: print(s.describe()) print("Largest:", max(shapes, key=lambda s: s.area()).describe())
Your Tasks
  • Complete the constructors for all three child classes. Ensure you properly call the parent class's initialization method to handle the color, then store the specific measurements.
  • Complete the area methods for all three child classes using the correct mathematical formulas.
  • Observe the describe() method in the parent class. Notice how it calls the area method, which automatically resolves to the correct child version. This demonstrates polymorphism.
  • Use the provided lambda function combined with a built-in function to find and print the shape that has the largest area.
Expected OutputRed Circle with area 153.94 Blue Rectangle with area 40.00 Green Triangle with area 30.00 Largest: Red Circle with area 153.94
💡 One Hint Remember to use the math module for the value of Pi. Make sure each child class is correctly overriding the parent's area method. The parent class's describe method will automatically call the correct child method.
01
Fibonacci with Iterator 🌀
ITERATORINTERFACEEASY~20 min
📖 Scenario
Java doesn't have yield, but you can get the same "one value at a time" behaviour by implementing the Iterator interface. You define hasNext() — does another value exist? — and next() — give me the next one. Java's for-each loop works with any Iterator automatically.
Starter Code
import java.util.*; class FibIterator implements Iterator<Integer> { private int a = 0, b = 1; private final int limit; FibIterator(int limit) { this.limit = limit; } public boolean hasNext() { return a <= limit; // still values left to produce } public Integer next() { int current = a; int temp = a + b; a = b; b = temp; return current; } } public class Main { public static void main(String[] args) { // Task 1: collect all Fibonacci numbers up to 50 FibIterator it = new FibIterator(50); List<Integer> all = new ArrayList<>(); while (it.hasNext()) all.add(it.next()); System.out.println("All up to 50: " + all); // Task 2 & 3 below } }
Your Tasks
  • Study the provided iterator logic and trace the variable swaps by hand for the first three iterations.
  • Write a loop that collects only the even Fibonacci numbers up to 50, and calculate their sum.
  • Write a custom loop that explicitly stops after pulling the first 8 numbers from the iterator.
  • Trace the hasNext() condition when the internal value reaches 55 to understand when the iterator flags that it is exhausted.
Expected OutputAll up to 50: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] Even fibs: [0, 2, 8, 34] Sum: 44 First 8: [0, 1, 1, 2, 3, 5, 8, 13]
💡 One Hint To get the first 8 values, think about combining the iterator's hasNext() check with a manual counter in a loop condition.
02
Matrix Operations 🔢
2D ARRAYNESTED LOOPSEASY~25 min
📖 Scenario
Matrices are used in game development (rotation/movement), image processing (each pixel is a cell), and machine learning (neural network weights). A matrix is a 2D grid. In Java, it's represented as a 2D array: int[][] matrix. Access any cell with matrix[row][col], get row count with matrix.length, column count with matrix[0].length. Today you'll transpose it, sum rows and columns, and find the diagonal.
Starter Code
import java.util.*; public class Matrix { public static void main(String[] args) { int[][] matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; // Task 1: transpose // Task 2: row sums // Task 3: column sums // Task 4: diagonal sum } }
Your Tasks
  • Initialize a new 3x3 array, then use nested loops to swap the coordinate positions from the original array to populate the transposed version. Print it row by row.
  • Calculate and print the sum of each row by iterating across the columns for every row index.
  • Calculate and print the sum of each column by iterating down the rows for every column index.
  • Find the diagonal sum efficiently by realizing you only need a single loop since the row and column coordinates are identical.
Expected OutputTranspose: [1, 4, 7] [2, 5, 8] [3, 6, 9] Row sums: [6, 15, 24] Column sums: [12, 15, 18] Diagonal sum: 15
💡 One Hint When printing 2D arrays in Java, remember that printing the array directly gives a memory address; you'll need an array utility method for each row. For column sums, think about swapping the order of your nested loops.
03
Balanced Brackets Checker 🔍
STACKDEQUEEASY~25 min
📖 Scenario
Every code editor — VS Code, IntelliJ, Eclipse — uses this exact algorithm to show a red underline when your brackets don't match. ([{}]) is valid. ([)] is not. The trick is using a Stack — push opening brackets on, pop when you see a closing one, check they match. In Java, use Deque<Character> as your stack. ArrayDeque is Java's recommended stack implementation.
🧠 Java Stack — Deque Deque<Character> stack = new ArrayDeque<>();
stack.push(ch) → push to top
stack.pop() → remove from top
stack.peek() → look at top without removing
stack.isEmpty() → check if empty (safer than size()==0)
Starter Code
import java.util.*; public class BracketChecker { static boolean isBalanced(String s) { Deque<Character> stack = new ArrayDeque<>(); for (char ch : s.toCharArray()) { if ("([{".indexOf(ch) >= 0) { stack.push(ch); } else if (")]}".indexOf(ch) >= 0) { if (stack.isEmpty()) return false; char top = stack.pop(); // TODO: check if top matches the closing bracket } } return stack.isEmpty(); } public static void main(String[] args) { String[] tests = {"(())", "([{}])", "(()", "([)]", ""}; for (String t : tests) System.out.println('"' + t + '"' + " → " + isBalanced(t)); } }
Your Tasks
  • Fill the TODO: Verify that the character popped from the stack is the exact matching opening bracket for the current closing character. Return false if there is a mismatch.
  • Run all 5 test strings and verify the output matches exactly.
  • Add one more test: "({[]})" — what should it return?
  • Why does an empty string return true? Trace through the loop.
Expected Output"(())" → true "([{}])" → true "(()" → false "([)]" → false "" → true
💡 One Hint Instead of a long chain of if/else statements, could a Map or a switch statement make checking matching pairs cleaner? Think about what state the stack is in if the string is entirely empty.
04
String Compression 🗜️
STRINGSTRINGBUILDEREASY~20 min
📖 Scenario
ZIP files, PNG images, and WhatsApp message compression all use some form of run-length encoding — a basic compression trick where you replace repeated characters with the character and a count. "aabcccdddd" becomes "a2bc3d4". If the compressed version is not shorter, keep the original. Key Java difference: never use + to build strings inside a loop — each + creates a brand new String object in memory. Use StringBuilder instead — it modifies in place and is dramatically faster.
Starter Code
public class Compress { static String compress(String s) { if (s.isEmpty()) return ""; StringBuilder sb = new StringBuilder(); // TODO: Iterate through 's', count consecutive characters // TODO: Append the character and its count (if > 1) to 'sb' // TODO: Don't forget to handle the final sequence of characters! return s; // Update this to return the shorter of the two } public static void main(String[] args) { String[] words = {"aabcccdddd", "abcd", "aaabba", "aaaaaa"}; for (String w : words) System.out.println('"' + w + "\" → \"" + compress(w) + '"'); } }
Your Tasks
  • Iterate through the string, counting consecutive repeating characters.
  • Append the character and its count (if > 1) to the StringBuilder when a sequence ends.
  • Ensure the final sequence of characters is appended after the loop terminates.
  • Return the compressed string only if its length is strictly less than the original string.
Expected Output"aabcccdddd" → "a2bc3d4" "abcd" → "abcd" "aaabba" → "a3b2a" "aaaaaa" → "a6"
💡 One Hint Just like in the Python version, the loop will finish without processing the very last sequence of characters. Remember to append it to the StringBuilder after the loop!
05
Shape Hierarchy — Inheritance 🔷
OOPINHERITANCEMEDIUM~30 min
📖 Scenario
A drawing app needs to handle circles, rectangles, and triangles. They all share common behaviour — a colour and a way to describe themselves — but each calculates area differently. This is the core of inheritance: a parent class defines shared behaviour, child classes override what's different. In Java, use the abstract keyword to force subclasses to implement a method. An abstract class cannot be instantiated directly.
Starter Code
abstract class Shape { String color; Shape(String color) { this.color = color; } abstract double area(); // subclasses MUST implement this String describe() { return String.format("%s %s with area %.2f", color, this.getClass().getSimpleName(), area()); } } class Circle extends Shape { double radius; Circle(String color, double radius) { super(color); this.radius = radius; } double area() { return /* TODO */ 0; } } class Rectangle extends Shape { double width, height; Rectangle(String c, double w, double h) { super(c); width=w; height=h; } double area() { return /* TODO */ 0; } } class Triangle extends Shape { double base, height; Triangle(String c, double b, double h) { super(c); base=b; height=h; } double area() { return /* TODO */ 0; } } public class Main { public static void main(String[] args) { Shape[] shapes = { new Circle("Red", 7), new Rectangle("Blue", 5, 8), new Triangle("Green", 6, 10), }; for (Shape s : shapes) System.out.println(s.describe()); Shape largest = shapes[0]; for (Shape s : shapes) if (s.area() > largest.area()) largest = s; System.out.println("Largest: " + largest.describe()); } }
Your Tasks
  • Implement the correct area calculation for the Circle class using the provided radius.
  • Implement the correct area calculation for the Rectangle class.
  • Implement the correct area calculation for the Triangle class.
  • Notice that the `Shape` array holds multiple different types of objects safely. Explain how polymorphism allows this to work.
Expected OutputRed Circle with area 153.94 Blue Rectangle with area 40.00 Green Triangle with area 30.00 Largest: Red Circle with area 153.94
💡 One Hint The `abstract` keyword acts as a strict contract. What happens if you try to create an object directly from an abstract class? Make sure your child classes fulfill the contract!
01
Fibonacci Generator 🌀
GENERATORFUNCTION*EASY~20 min
📖 Scenario
JavaScript has native generator functions using function* syntax — almost identical to Python's yield. They're used in async programming, infinite sequences, and lazy data pipelines. They work the same as Python generators — pause at yield, resume on next call.
🧠 JS Generator Syntax function* name() { yield value; } ← the * makes it a generator
const gen = name(); ← creates the generator object
gen.next() ← returns { value: X, done: false }
gen.next().value ← get just the value
When exhausted: { value: undefined, done: true }
Starter Code
function* fibonacci(limit) { let a = 0, b = 1; while (a <= limit) { yield a; [a, b] = [b, a + b]; // JS destructuring swap — no temp variable } } // Write your code below
Your Tasks
  • Iterate over the generator up to 50 and collect all yielded values into an array to print. Look into ES6 iterable looping or array spreading syntax.
  • Filter the generated list to isolate the even numbers, then calculate their total sum.
  • Write a loop that manually calls the generator function to extract only the first 8 values.
  • Review the destructuring assignment logic used for the variable swap. Explain how it eliminates the need for a temporary variable.
Expected OutputAll up to 50: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] Even fibs: [0, 2, 8, 34] Sum: 44 First 8: [0, 1, 1, 2, 3, 5, 8, 13]
💡 One Hint Is there a modern ES6 syntax trick to unpack all yielded values from a generator directly into an array? For the sum, consider chaining array methods.
02
Matrix Operations 🔢
ARRAYSMAP/REDUCEEASY~25 min
📖 Scenario
Matrices are used in game development (rotation/movement), image processing, and machine learning. JS arrays of arrays work as a 2D grid. Access cells with matrix[row][col]. Bonus: you can use .map() and .reduce() for some operations instead of nested for loops — this is the idiomatic modern JS way.
Starter Code
const matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]; // Write your code below
Your Tasks
  • Generate the transposed matrix. You may use traditional nested loops or leverage modern array mapping techniques.
  • Calculate the sum of each row. Using array reduction is highly recommended here.
  • Calculate the sum of each column. Think about how to structure an outer map against the columns and an inner reduction against the rows.
  • Calculate the diagonal sum efficiently using a single loop or reduction.
Expected OutputTranspose: [1, 4, 7] [2, 5, 8] [3, 6, 9] Row sums: [6, 15, 24] Column sums: [12, 15, 18] Diagonal sum: 15
💡 One Hint When using reduce or map on the matrix, remember that the callback function's second argument gives you the current index, which is very handy for finding the diagonal!
03
Balanced Brackets Checker 🔍
STACKARRAYEASY~25 min
📖 Scenario
Every code editor uses this exact algorithm to show a red underline when brackets don't match. ([{}]) is valid. ([)] is not. The trick is using a Stack — push opening brackets on, pop when you see a closing one, check they match. JavaScript uses a regular array as the stack. .push() adds to the end, .pop() removes from the end.
Starter Code
function isBalanced(s) { const stack = []; const pairs = { ')': '(', ']': '[', '}': '{' }; for (const ch of s) { if ('([{'.includes(ch)) { // TODO: push to stack } else if (')]}'.includes(ch)) { // TODO: check stack not empty, top matches, then pop } } return /* TODO: stack is empty */; } const tests = ["(())", "([{}])", "(()", "([)]", ""]; tests.forEach(t => console.log(`"${t}" → ${isBalanced(t)}`));
Your Tasks
  • Fill the first TODO by pushing the valid opening bracket into your tracking array.
  • Fill the second TODO by validating the closing bracket against the top item in your tracking array. Handle edge cases where the array might already be empty.
  • Ensure the final return statement properly evaluates whether all brackets were successfully matched and closed.
  • Think about array mechanics: How does JavaScript handle pulling the last item from an array differently than a native Queue?
Expected Output"(())" → true "([{}])" → true "(()" → false "([)]" → false "" → true
💡 One Hint In JavaScript, what does pop() return if the array is already empty? Make sure you check the array's length before trying to match brackets!
04
String Compression 🗜️
STRINGLOOPSEASY~20 min
📖 Scenario
ZIP files, PNG images, and WhatsApp message compression all use some form of run-length encoding — a basic compression trick where you replace repeated characters with the character and a count. "aabcccdddd" becomes "a2bc3d4". If the compressed version is not shorter, keep the original. JS strings are immutable — don't build the result with += in a loop if you can avoid it. Use an array to collect parts and join at the end.
Starter Code
function compress(s) { if (!s) return ""; const parts = []; // TODO: Iterate through 's', count consecutive characters // TODO: Push the character and its count (if > 1) to 'parts' // TODO: Don't forget to handle the final sequence of characters! const result = parts.join(""); return result; // Update to return the shorter of the two } ["aabcccdddd", "abcd", "aaabba", "aaaaaa"].forEach(w => console.log(`"${w}" → "${compress(w)}"`));
Your Tasks
  • Iterate through the string, counting consecutive repeating characters.
  • Push the character and its count (if > 1) into the parts array when a sequence ends.
  • Ensure the final sequence of characters is pushed into the array after the loop concludes.
  • Return the joined string only if it is strictly shorter than the original string; otherwise, return the original.
Expected Output"aabcccdddd" → "a2bc3d4" "abcd" → "abcd" "aaabba" → "a3b2a" "aaaaaa" → "a6"
💡 One Hint Pushing pieces into an array and joining them at the end is much more efficient than using string concatenation in a loop. Don't forget to handle the final sequence of characters after the loop terminates.
05
Shape Hierarchy — Inheritance 🔷
OOPCLASSMEDIUM~30 min
📖 Scenario
A drawing app needs to handle circles, rectangles, and triangles. They all share common behaviour — a colour and a way to describe themselves — but each calculates area differently. This is inheritance. JS uses extends and super(). JS has no abstract keyword — enforce method implementation by throwing an error in the base class.
Starter Code
class Shape { constructor(color) { this.color = color; } area() { throw new Error("area() must be implemented"); } describe() { return `${this.color} ${this.constructor.name} with area ${this.area().toFixed(2)}`; } } class Circle extends Shape { constructor(color, radius) { super(color); this.radius = radius; } area() { return /* TODO */ 0; } } class Rectangle extends Shape { constructor(color, w, h) { super(color); this.w = w; this.h = h; } area() { return /* TODO */ 0; } } class Triangle extends Shape { constructor(color, b, h) { super(color); this.b = b; this.h = h; } area() { return /* TODO */ 0; } } const shapes = [new Circle("Red",7), new Rectangle("Blue",5,8), new Triangle("Green",6,10)]; shapes.forEach(s => console.log(s.describe())); const largest = shapes.reduce((a, b) => a.area() > b.area() ? a : b); console.log("Largest:", largest.describe());
Your Tasks
  • Implement the proper mathematical area formula for the Circle class.
  • Implement the proper mathematical area formula for the Rectangle class.
  • Implement the proper mathematical area formula for the Triangle class.
  • Analyze how this.constructor.name operates dynamically within the parent describe() method to pull the specific class identity.
Expected OutputRed Circle with area 153.94 Blue Rectangle with area 40.00 Green Triangle with area 30.00 Largest: Red Circle with area 153.94
💡 One Hint Need to square a number? Look into the exponentiation operator. To format the output nicely, there's a handy string method for numbers that fixes the decimal places.
01
LIKE — Pattern Matching 🔎
LIKEWHEREEASY~15 min
📖 Scenario
A search bar on any website — Google, Amazon, Zomato — uses pattern matching to find results. In SQL, LIKE lets you search for partial matches inside text columns. Two wildcards: % matches any number of characters, _ matches exactly one character.
🗄️ Concept: LIKE Wildcards
% means "zero or more of anything" — like a * in search.
_ means "exactly one character" — any single character.
These go inside the string after LIKE. Think of it like autocomplete — you're describing the shape of the value you're looking for, not the exact value.
TABLE: students
idnamecitymarksgrade
1'Rahul''Delhi'72'B'
2'Priya''Mumbai'91'A'
3'Arjun''Delhi'38'F'
4'Sneha''Pune'85'A'
5'Vikram''Mumbai'55'C'
6'Anita''Delhi'94'A'
7'Rohan''Pune'43'F'
Your Tasks
  • Query the table to find all students whose name begins with a specific starting letter.
  • Write a query that locates records where the name terminates with a specific ending letter.
  • Find students where a specific letter is present anywhere within the city field.
  • Construct a query using wildcards to return only the students whose names are a specific, exact character length.
① Names starting with A
name
Arjun
Anita
② Names ending with a
name
Priya
Sneha
Anita
③ City contains 'u'
namecity
PriyaMumbai
SnehaPune
VikramMumbai
RohanPune
💡 One Hint Think about the difference between % and _. One represents any number of characters, while the other represents exactly one. How can you combine them to specify exact lengths?
02
IN and BETWEEN — Clean Filters 🎯
INBETWEENNOT INEASY~15 min
📖 Scenario
Instead of writing WHERE city = 'Delhi' OR city = 'Pune', SQL gives you IN — a cleaner way to match any value from a list. Instead of WHERE marks >= 50 AND marks <= 80, use BETWEEN — it's more readable and inclusive on both ends.
🗄️ Concept: IN and BETWEEN
IN is like asking "is this value in this list?" — it replaces multiple OR conditions.
BETWEEN x AND y checks if a value falls in a range, including both x and y.
NOT IN and NOT BETWEEN are the opposites — everything outside the list or range.
TABLE: students (same as Q1)
idnamecitymarksgrade
1'Rahul''Delhi'72'B'
2'Priya''Mumbai'91'A'
3'Arjun''Delhi'38'F'
4'Sneha''Pune'85'A'
5'Vikram''Mumbai'55'C'
6'Anita''Delhi'94'A'
7'Rohan''Pune'43'F'
Your Tasks
  • Filter the results using an inclusion list to return specific grades.
  • Filter the students based on an inclusive numerical range for their marks.
  • Retrieve records that match multiple potential city locations without writing an OR chain.
  • Construct an exclusion query that removes students from a specific city from the result set.
① Grade A or B
namegrademarks
RahulB72
PriyaA91
SnehaA85
AnitaA94
② Marks between 50 and 80
namemarks
Rahul72
Vikram55
💡 One Hint Remember that BETWEEN includes both the starting and ending boundaries. Use IN to avoid writing long chains of OR conditions.
03
CASE WHEN — If/Else in SQL 🔀
CASE WHENTHENMEDIUM~20 min
📖 Scenario
Report cards need labels like "Distinction", "Pass", "Fail" — not raw numbers. CASE WHEN is SQL's if/else — you write conditions, and for each row SQL picks the first condition that is true and returns that value. It lets you create a new calculated column right inside your SELECT.
🗄️ Concept: CASE WHEN
Think of it as an if/elif/else chain that produces a value for each row.
It goes inside the SELECT list — it creates a new column in the results.
Conditions are checked top to bottom — the first one that matches wins.
Always end with ELSE to handle rows that don't match any condition, then close with END.
TABLE: students (same table)
idnamemarksgrade
1'Rahul'72'B'
2'Priya'91'A'
3'Arjun'38'F'
4'Sneha'85'A'
5'Vikram'55'C'
6'Anita'94'A'
7'Rohan'43'F'
Your Tasks
  • Create a query that generates a new custom column assigning a performance label based on numerical thresholds.
  • Implement a sorting directive to order the generated result set from highest marks to lowest.
  • Embed a secondary conditional column into the query that assigns a binary category (e.g., Senior/Junior) based on a cut-off point.
  • Combine conditional logic with an aggregate function to produce a summary count of students in each performance tier.
① Result — name, marks, band (sorted by marks desc)
namemarksband
Anita94Distinction
Priya91Distinction
Sneha85Distinction
Rahul72First Class
Vikram55Pass
Rohan43Fail
Arjun38Fail
💡 One Hint The order of your WHEN conditions is critical! SQL evaluates them from top to bottom and stops at the first match. Should you start checking the highest values or the lowest values first?
04
Subqueries — Query Inside a Query 🪆
SUBQUERYWHEREMEDIUM~25 min
📖 Scenario
Sometimes the value you want to filter by is itself calculated from the data. "Find students above the class average" — you don't know the average until you query it! A subquery is a query inside parentheses inside another query. The inner query runs first, the result is used by the outer query.
🗄️ Concept: Subquery
A subquery sits inside parentheses and is treated as a single value (or set of values) by the outer query.
The inner query runs first, produces a result, then the outer query uses it.
Common use: WHERE column > (SELECT AVG(column) FROM table)
Think of it like a variable in Python: first calculate something, then use that result in a condition.
TABLE: students (same table)
idnamecitymarksgrade
1'Rahul''Delhi'72'B'
2'Priya''Mumbai'91'A'
3'Arjun''Delhi'38'F'
4'Sneha''Pune'85'A'
5'Vikram''Mumbai'55'C'
6'Anita''Delhi'94'A'
7'Rohan''Pune'43'F'
Your Tasks
  • Write a query that filters rows based on an aggregate calculation dynamically performed on the entire table.
  • Formulate a query to extract the top-performing records grouped by a specific category. This requires relating the inner query back to the outer query.
  • Filter the full table against an aggregate value derived from a highly restricted subset of the table.
  • Validate your subquery logic by manually performing the baseline calculation.
① Above average (avg = 68.29)
namemarks
Rahul72
Priya91
Sneha85
Anita94
② Top scorer per city
namecitymarks
AnitaDelhi94
PriyaMumbai91
SnehaPune85
💡 One Hint For task 2, your subquery needs to relate back to the outer query so it calculates the max marks specifically for the current row's city. This is called a correlated subquery!
05
Mixed Bag — All Day 8 SQL 🎯
LIKEINCASESUBQUERYMEDIUM~25 min
📖 Scenario
Final challenge — combine everything from today. Each query uses at least two of the concepts you've learned: LIKE, IN, BETWEEN, CASE WHEN, and Subqueries. Real-world SQL queries always combine multiple features — this is where things get genuinely useful.
TABLE: students (same table — all 7 rows)
idnamecitymarksgrade
1'Rahul''Delhi'72'B'
2'Priya''Mumbai'91'A'
3'Arjun''Delhi'38'F'
4'Sneha''Pune'85'A'
5'Vikram''Mumbai'55'C'
6'Anita''Delhi'94'A'
7'Rohan''Pune'43'F'
Your Tasks — one query per task
  • Construct a complex WHERE clause that merges wildcard pattern matching with a list exclusion directive. Use parentheses to control evaluation order.
  • Create a query that merges conditional CASE logic with a dynamic Subquery to assign a relative performance tag.
  • Chain a list inclusion filter with a numerical range boundary to isolate a specific cross-section of records.
  • Perform a grouped aggregation across a column that is actively generated via conditional logic within the query itself.
① A or R names, not Mumbai
namecity
RahulDelhi
ArjunDelhi
AnitaDelhi
RohanPune
④ Count per band
bandcount
Distinction3
First Class1
Pass1
Fail2
💡 One Hint When combining AND and OR conditions, use parentheses to ensure they are evaluated in the correct order. For task 4, you can actually GROUP BY a column you just created with a CASE statement!