SQL For Kids
SQL For Kids
Databases!
Left Join: All toys from your box, and matching ones from another
Right Join: All toys from the other box, and matching ones from yours
What is SQL?
Imagine you have a super-duper toy box, but it's not just any toy box. It's a magic toy
box that can hold millions and millions of toys! This magic toy box is like a database.
Now, how do you talk to this magic toy box? How do you tell it to find your favorite red
car, or count all your action figures? You use SQL! SQL (which stands for Structured
Query Language) is like the secret language you use to talk to databases. It's a special
set of magic words that helps you ask questions and give commands to your toy box.
Think of it like this: - Database: Your super-duper magic toy box. - SQL: The magic
words you use to talk to the toy box.
With SQL, you can: - Find specific toys (like your red car). - Add new toys to your
collection. - Take out old toys you don't play with anymore. - Change details about
your toys (like giving your teddy bear a new name).
It's all about organizing and managing your toys (which are like data in a database) so
you can find them easily and keep everything neat and tidy!
SELECT tells the database what you want to see. You can pick specific things, like just
the names of your toys, or you can pick everything!
SELECT toy_name
If you want to see everything about your toys (like their name, color, and size):
SELECT *
After you tell SQL what you want to see with SELECT , you need to tell it where to find
it. That's what FROM is for!
FROM tells the database which toy box (or table) to look in.
SELECT toy_name
FROM MyToys
1.3 WHERE: Finding Toys with Special Powers
Sometimes you don't want to see all the toys, even from a specific toy box. Maybe you
only want to see the red cars, or the dolls that can sing. WHERE helps you find toys that
have special qualities.
WHERE is like a filter. It helps you pick out only the toys that match certain rules.
Example: If you want to find all the red cars in your MyToys toy box:
After you've picked out your toys, you might want to arrange them nicely. Maybe you
want to see them from smallest to biggest, or in alphabetical order by their names.
ORDER BY helps you do that!
ORDER BY sorts your toys. You can sort them ASC (from A to Z, or smallest to biggest)
or DESC (from Z to A, or biggest to smallest).
Example: If you want to see your toys sorted by their names, from A to Z:
SELECT toy_name
FROM MyToys
ORDER BY toy_name ASC
If you want to see your toys sorted by their size, from biggest to smallest:
Just like you have different kinds of toys (cars, dolls, blocks), databases have different
kinds of data types. These tell the database what kind of information is stored in each
part of your toy box.
Here are some common data types: - Text (VARCHAR/TEXT): For words and names,
like 'Teddy Bear' or 'Blue'. - Numbers (INT/INTEGER): For whole numbers, like 5 cars
or 10 blocks. - Numbers with decimals (DECIMAL/FLOAT): For numbers with parts,
like 3.5 inches tall. - Dates (DATE/DATETIME): For dates and times, like '2025-07-25' or
'2025-07-25 10:30:00'.
Understanding data types helps the database store and find your information
correctly!
Imagine you have two toy boxes. One has your toys, and the other has your friend's
toys. What if you want to find out which toys you both have? Or see all the toys from
both boxes together? That's where joins come in!
Joins are like building a bridge between two toy boxes (tables) so you can see the toys
from both at the same time.
Inner Join: Toys that are in BOTH boxes
An INNER JOIN shows you only the toys that are in both toy boxes. It's like finding the
toys that you and your friend both have in your collections.
Example: If you have a toy box called MyToys and your friend has one called
FriendsToys , and you want to see which toys you both have:
A LEFT JOIN shows you all the toys from your toy box ( MyToys ), and if your friend has
any of the same toys, it will show those too. If your friend doesn't have a matching toy,
it will just show an empty space for that toy.
Example:
A RIGHT JOIN is the opposite of a LEFT JOIN . It shows you all the toys from your
friend's toy box ( FriendsToys ), and if you have any of the same toys, it will show
those too.
Example:
A FULL JOIN (sometimes called FULL OUTER JOIN ) shows you all the toys from both
toy boxes. If a toy is only in your box, it shows up. If it's only in your friend's box, it
shows up. And if it's in both, it shows up too!
Example:
Sometimes, you might want to compare toys within the same toy box. For example,
maybe you want to find pairs of toys that are the same color, even if they have
different names. This is where a SELF JOIN comes in handy. It's like making a copy of
your toy box and then joining it with the original.
Example: If you want to find pairs of toys in MyToys that are the same color but have
different names:
Imagine you have a big pile of toys, and you want to know some quick facts about
them. How many toys do you have? What's the most expensive toy? What's the
average size of your action figures? Aggregations help you answer these kinds of
questions!
Aggregations are like special calculators that look at a whole group of toys and give
you one answer.
COUNT: How Many Toys?
COUNT tells you how many toys (or rows) are in your toy box, or how many toys fit a
certain rule.
SELECT COUNT(*)
FROM MyToys
SELECT COUNT(*)
FROM MyToys
WHERE color = 'red'
If your toys have points or values, SUM adds them all up for you.
SELECT SUM(value)
FROM MyToys
AVG calculates the average of a group of numbers. Like the average size of all your toy
cars.
Example:
SELECT AVG(size)
FROM MyToys
MIN finds the smallest number (like the smallest toy size), and MAX finds the biggest
number (like the biggest toy size).
Example:
SELECT MIN(size), MAX(size)
FROM MyToys
What if you want to know how many toys of each color you have? Or the average size
of toys for each type? GROUP BY helps you put your toys into different piles based on
something they have in common, and then you can use COUNT , SUM , AVG , etc., on
each pile.
WHERE helps you filter individual toys. But what if you want to filter groups of toys? For
example, you only want to see colors where you have more than 5 toys. That's when
you use HAVING .
Example: To see only the colors where you have more than 5 toys:
Imagine you want to find out which of your toys are bigger than the average size of all
your toys. To do this, you first need to know the average size, and then you can
compare each toy to that average.
A subquery is like asking a secret question inside another question. The secret
question (the subquery) gets answered first, and then its answer is used in the main
question.
In this example, (SELECT AVG(size) FROM MyToys) is the subquery. It first finds the
average size of all toys, and then the main query uses that average to find toys that are
bigger.
Subqueries can be used in different places: - In WHERE : Like the example above, to
filter rows based on a secret answer. - In FROM : To create a temporary toy box (table)
that you can then ask more questions about. - In SELECT : To show a secret answer
next to each toy.
SQL functions are like special tools that help you do cool things with your toy data.
They can change how your toy names look, help you work with dates, or do math with
your toy sizes.
These functions help you work with text, like the names of your toys.
CONCAT: This tool helps you stick two pieces of text together. Imagine you have a
toy named 'Super' and another named 'Robot'. You can CONCAT them to make
'SuperRobot'.
Example:
SUBSTRING: This tool lets you grab only a part of a toy's name. If your toy is
named 'Dragonfly', you could use SUBSTRING to just get 'Dragon'.
Example:
These functions help you work with dates and times, like when you got a toy or when it
was made.
DATEADD: This tool lets you add time to a date. If you got a toy today, you could
use DATEADD to see what date it will be in 7 days.
Example:
DATEDIFF: This tool helps you find the difference between two dates. How many
days have passed since you got your favorite toy?
Example:
These functions help you do calculations with numbers, like toy sizes or values.
ROUND: This tool helps you make numbers neater by rounding them. If a toy is
3.7 inches tall, ROUND can make it 4 inches.
Example:
CEILING: This tool always rounds a number up to the next whole number. If a toy
is 3.1 inches tall, CEILING makes it 4.
Example:
SELECT CEILING(size)
FROM MyToys
These functions are like having a special toolbox for all your toy data!
Chapter 3: Advanced SQL - Database Superpowers!
We've learned about INNER , LEFT , RIGHT , and FULL joins. These are like connecting
toy boxes in different ways. But there are a couple more special ways to connect them!
Imagine you want to pair up every single toy from your toy box with every single toy
from your friend's toy box. A CROSS JOIN does exactly that! It creates every possible
combination. Be careful though, if you have many toys, this can make a HUGE list!
Example: If you have 3 toys and your friend has 2 toys, a CROSS JOIN will give you 3 *
2 = 6 pairs.
A NATURAL JOIN is a bit like an INNER JOIN , but it's super smart! It automatically
looks for columns with the same name in both toy boxes and joins them based on
those matching names. You don't even have to tell it which columns to join on!
Example: If both MyToys and FriendsToys have a column called toy_id , a NATURAL
JOIN will automatically use that to connect them.
SELECT *
FROM MyToys
NATURAL JOIN FriendsToys
It's handy, but you need to be sure the columns with the same names are truly meant
to be joined!
3.2 Window Functions: Looking at Toys in a Special Way
Imagine you have a list of all your toys, and you want to know how each toy's size
compares to the other toys in its group (like all the cars, or all the dolls). Or maybe you
want to see the biggest toy in each group. Window functions help you do this!
Window functions are like looking at a 'window' of your data. They perform
calculations across a set of table rows that are related to the current row. It's like
having a special magnifying glass that lets you see a small part of your toy collection
and do calculations just on that part, without changing the whole list.
ROW_NUMBER(), RANK(), DENSE_RANK(): Giving Your Toys a Number
These functions help you give a number to each toy based on some order. Imagine
lining up all your toys from tallest to shortest and giving them a number.
ROW_NUMBER(): Gives a unique number to each toy in the order you specify. If
two toys are the same height, they still get different numbers.
Example:
RANK(): Gives a number, but if two toys are the same (like the same height), they
get the same rank, and the next toy skips a number.
Example:
DENSE_RANK(): Similar to RANK() , but if two toys are the same, they get the
same rank, and the next toy does not skip a number.
Example:
These functions help you look at toys that are just before or just after the current toy in
your sorted list, or divide your toys into equal groups.
LEAD(): Lets you look at the toy that comes after the current toy in your sorted
list.
Example:
Example:
Example:
Window functions are powerful tools for doing calculations on parts of your data
without grouping everything together!
3.3 Normalization: Keeping Your Toy Boxes Super Organized
Imagine you have a toy box, and in it, you write down everything about your toys: their
name, color, size, where you bought them, and even the name of the shop owner. If
you have many toys from the same shop, you might write the shop name and owner
name many times. This can get messy and take up too much space!
Normalization is like a super-smart way to organize your toy boxes so that you don't
repeat information. It helps keep your data neat, tidy, and easy to update.
Think of it like this: - Instead of writing the shop name and owner name for every toy,
you create a separate small toy box just for shops. In this shop toy box, you list each
shop only once, with its owner. - Then, in your main toy box, instead of writing the full
shop name, you just write a special number that points to the shop in the shop toy
box.
This way, if a shop owner changes their name, you only have to change it in one place
(the shop toy box), not for every single toy!
There are different levels of normalization, like 1NF, 2NF, and 3NF, which are just
different rules to make your toy boxes more and more organized.
Imagine you and your friend are playing with your toys, and you want to swap a toy.
You give your friend a car, and your friend gives you a doll. What if, in the middle of the
swap, something goes wrong? Maybe your friend drops the doll, or you accidentally
keep both the car and the doll!
In databases, when you make changes, like adding, removing, or changing data, it's
like making a toy swap. These changes are called transactions. A transaction is a
single, logical unit of work. It's a group of actions that should either all happen
successfully, or none of them should happen at all.
Think of it like this: - BEGIN: You say, "Okay, I'm starting a toy swap!" All the actions
you do now are part of this one big swap. - COMMIT: If everything goes perfectly, you
say, "Great! The swap is done, and it's official!" All the changes are saved. -
ROLLBACK: If something goes wrong in the middle, you say, "Oh no! Let's pretend this
never happened and put everything back the way it was before we started." All the
changes are undone.
This idea is super important and is often described by something called ACID
properties: - Atomicity: All or nothing. Like a toy swap, either both toys change hands,
or neither does. - Consistency: The database always stays in a good, valid state. No toy
should disappear or magically appear. - Isolation: If you and your friend are doing
separate toy swaps at the same time, your swaps shouldn't mess with each other. It's
like having separate play areas. - Durability: Once a swap is COMMIT ted, it's
permanent. Even if the lights go out, your toys are still where they should be.
Concurrency is about many people (or programs) trying to make toy swaps
(transactions) at the same time. Databases have clever ways to handle this, like using
locks, to make sure that when one person is playing with a toy, another person
doesn't accidentally try to change it at the same time and cause a mess. It's like
saying, "I'm playing with this toy right now, please wait your turn!"
Imagine you have a super big toy box with millions of toys! When you ask SQL to find
something, it might take a long, long time if it has to look at every single toy. Query
Performance Optimization is all about making SQL find your toys super fast!
Imagine your toy box has a special list, like a table of contents in a book. This list tells
you exactly where to find your red car, or all your action figures. This special list is
called an index.
When you have an index, SQL doesn't have to look at every toy. It can just look at the
index, find where the toys are, and go straight to them! This makes finding toys much,
much faster.
Example: If you often search for toys by their color, you could create an index on the
color of your toys. Then, when you ask for all red toys, SQL uses the index to quickly
jump to all the red toys without checking every single toy.
When you ask SQL to find toys, it has a plan. It decides the best way to look for them.
The EXPLAIN command is like asking SQL, "Hey, how are you going to find these toys?
Show me your plan!"
When you use EXPLAIN , SQL tells you step-by-step how it will execute your magic
words (your query). This helps you see if it's using the index, or if it's still looking at
every toy one by one. If it's slow, you can use EXPLAIN to figure out why and make it
faster.
There are many smart ways to make your SQL magic words faster: - Be specific: Don't
ask for more toys than you need. - Use indexes: Make sure you have indexes on the
things you search for often. - Avoid unnecessary steps: Sometimes, the way you ask
your question can make SQL do extra work. Learning to ask questions in a simpler,
more direct way can make a big difference.
It's like learning the fastest way to clean your room – you don't just throw everything
around, you have a smart strategy!
Imagine you have a special set of magic words that you use all the time to do a
complicated task, like finding all your red cars, then counting them, and then
arranging them by size. Instead of saying all those magic words every single time,
wouldn't it be great if you could just say one special word that does all of that for you?
That's what a Stored Procedure is! It's like a pre-written magic spell or a recipe that
you save in your database. You write it once, give it a name, and then whenever you
need to do that complicated task, you just call its name, and the database knows
exactly what to do.
Benefits of Stored Procedures: - Faster: Because the database already knows the
steps, it can run them very quickly. - Easier to use: You just call one name instead of
writing many lines of SQL. - Safer: You can give people permission to use the stored
procedure without letting them see or change the complicated magic words inside. -
Reusable: You can use the same stored procedure over and over again.
EXEC FindMyRedCars
This one line would do all the complicated steps you saved inside the FindMyRedCars
stored procedure.
Sometimes, you might want to tell the stored procedure something special when you
call it, like FindMyRedCars but only for cars bigger than 5 inches. You can give it input
parameters, which are like special instructions you give to your magic spell.
Imagine you have a special rule for your toy box: every time you put a new toy in, you
automatically write its name in a special notebook. Or, every time you take a toy out,
you automatically update a count of how many toys are left.
That's what a Trigger is! A trigger is like an automatic action that happens in your
database when something specific occurs. It's a special kind of stored procedure that
runs automatically when you INSERT (put in), UPDATE (change), or DELETE (take out)
data from a toy box (table).
Types of Triggers: - AFTER Trigger: This trigger runs after the main action (like
putting a toy in) has finished. - BEFORE Trigger: This trigger runs before the main
action happens. You can use it to check if the action is allowed or to change something
before it's saved. - INSTEAD OF Trigger: This trigger runs instead of the main action.
It's like saying, "Don't actually put the toy in the box, do this other thing instead!"
Example: Imagine you have a trigger that automatically updates a counter of how
many toys you have every time you add a new toy:
-- This is just an idea, actual trigger code is more complex!
CREATE TRIGGER UpdateToyCount
AFTER INSERT ON MyToys
FOR EACH ROW
BEGIN
UPDATE ToyStats SET total_toys = total_toys + 1;
END;
Triggers are great for making sure rules are always followed and for automating tasks
in your database!
Imagine you have a big, messy toy box, but you only want to show your friends a
special collection of your favorite cars, neatly arranged. You don't want to move the
actual cars, just create a special display case that shows only those cars.
That's what a View is in SQL! A view is like a virtual toy box or a special display case. It
doesn't actually store any data itself; instead, it's a saved SQL query that acts like a
table. When you look at a view, it's like looking through a window at the data in your
real toy boxes, but only seeing what you've chosen to display.
Benefits and Usage of Views: - Simplicity: You can hide complicated joins and filters
behind a simple view. Your friends (or other users) don't need to know the complex
magic words to see your special collection. - Security: You can show only certain toys
(data) to certain friends (users), hiding the rest of the toy box from them. -
Consistency: If you often need to see the same special collection of toys, a view
ensures you always see it the same way.
Example: If you always want to see only your red cars and blue dolls, you can create a
view for it:
Now, whenever you want to see this special collection, you just query the view as if it
were a real table:
We already learned about COUNT , SUM , AVG , MIN , and MAX to count and measure our
toys. But sometimes, you need even more clever ways to summarize your toy
collection. That's where Advanced Aggregations come in!
Imagine you want to count how many of your toys are 'small', 'medium', or 'large'
based on their size. A CASE statement is like a smart helper that looks at each toy and
decides which group it belongs to based on rules you give it.
Example:
SELECT
SUM(CASE WHEN size < 5 THEN 1 ELSE 0 END) AS SmallToys,
SUM(CASE WHEN size >= 5 AND size < 10 THEN 1 ELSE 0 END) AS MediumToys,
SUM(CASE WHEN size >= 10 THEN 1 ELSE 0 END) AS LargeToys
FROM MyToys;
Imagine you have toys of different colors and types (e.g., red cars, blue dolls). You
might want to know: - How many toys of each color? - How many toys of each type? -
How many toys of each color and type? - And the total number of all toys?
CUBE and ROLLUP are like super-summary tools that can give you all these different
totals with just one query!
ROLLUP: Gives you summaries at different levels, like totals for each color, and
then a grand total for all toys.
Example:
SELECT color, type, COUNT(*)
FROM MyToys
GROUP BY ROLLUP(color, type);
This would show you counts for each color-type combination, then counts for each
color (ignoring type), and finally a total count for all toys.
CUBE: Gives you summaries for all possible combinations of the things you
group by. So, it would give you counts for color-type, just color, just type, and the
grand total.
Example:
CUBE is like getting every possible summary you can imagine from your toy groups!
Imagine you have a new friend who wants to share their toy collection with you, but
their toys are all listed in a special file on their computer. Or maybe you want to share
your toy list with someone else. Data Import/Export is how you get data into and out
of your database.
CSV (Comma Separated Values): This is like a simple list where each toy's
information is separated by commas. It's a very common way to share simple
lists of things.
JSON (JavaScript Object Notation): This is like a more organized list, where
each toy's details are grouped together with curly brackets {}. It's often used for
sharing data between computer programs.
XML (Extensible Markup Language): This is another way to organize data with
special tags, like Car. It's a bit like a structured document.
Databases have special tools that can read these files and put all the toy information
into your toy boxes (tables).
Exporting Query Results: Sharing Your Toy Lists
Just like you can bring data in, you can also take data out! After you use your SQL
magic words to find and organize your toys, you can save that list into a file (like a CSV
or JSON file) to share with others or use in other programs.
Example: If you want to share a list of all your red toys, you can run your SELECT
query and then tell the database to save the results into a CSV file. This is super useful
for making reports or sharing specific parts of your toy collection!
So far, we've mostly talked about connecting two toy boxes. But what if your toy world
is much bigger? Imagine you have: - A toy box for Cars - A toy box for Dolls - A toy
box for ToyOwners (who owns which toy) - A toy box for ToyStores (where each toy
was bought)
When you have many toy boxes that are all connected, you have a Complex Data
Model. It's like building a whole city of toy boxes, all linked together!
To understand everything about a toy in this big world, you might need to look in
many different toy boxes. For example, to find out the name of a car, who owns it, and
which store it came from, you would need to connect the Cars toy box, the
ToyOwners toy box, and the ToyStores toy box. This is called a multi-table join.
Example:
SELECT
C.car_name,
O.owner_name,
S.store_name
FROM Cars C
INNER JOIN ToyOwners O ON C.owner_id = O.owner_id
INNER JOIN ToyStores S ON C.store_id = S.store_id;
This query connects three toy boxes to get all the information you need about your
cars!
Transformations with JOIN and GROUP BY: Reshaping Your Toy Data
Sometimes, you need to take data from many toy boxes and then change it or
summarize it in a new way. For example, you might want to see how many toys each
store has sold, and what the average price of toys from each store is.
You can use JOIN to bring all the information together and then GROUP BY to
summarize it. This is like taking all the toys from different boxes, putting them into
new piles based on the store they came from, and then counting and averaging things
in each pile.
Example:
SELECT
S.store_name,
COUNT(T.toy_id) AS total_toys_sold,
AVG(T.price) AS average_toy_price
FROM ToyStores S
INNER JOIN Toys T ON S.store_id = T.store_id
GROUP BY S.store_name;
This helps you understand your big toy world better by combining and transforming
information from different places!
Imagine your toy box is a bit messy. Some toys might be duplicated (you have two
identical red cars!), some might be missing parts (a doll without an arm), or some
information might be wrong (a blue car listed as red). Data Cleaning is like tidying up
your toy box to make sure all your toy information is perfect and ready to play with!
Sometimes, you might accidentally have the same toy listed twice in your toy box. This
can happen if you add the same toy information more than once. Removing duplicates
means finding these extra copies and getting rid of them so you only have one entry
for each unique toy.
Example: If you have two entries for the exact same red car, you would use SQL to find
and remove one of them, so your list is accurate.
Handling Missing Data: Finding Missing Toy Parts
What if some of your toy entries are missing information? Maybe a toy has a name and
a color, but no size listed. This is like a doll missing an arm – it's not complete.
Handling missing data means deciding what to do with these incomplete entries. You
might: - Fill in the blanks: If you know the missing information, you can add it. -
Ignore them: Sometimes, if the missing information isn't important for what you're
doing, you might just ignore those toys. - Remove them: If too much information is
missing, you might decide to remove that toy entry completely.
Data cleaning is a very important step to make sure your database is reliable and your
SQL magic words give you the best answers!
Here are some tricky questions to test your SQL superpowers! Don't worry if they seem
hard at first. Thinking about them will help you understand SQL even better.
Imagine you have a toy box called AllToys with columns toy_id , toy_name , and
color . You also have a list of your favorite toys in a separate list, but it's not a table.
It's just a list: ( 'Teddy Bear', 'Red Car', 'Blue Robot' )
How would you find all the toys in your AllToys toy box that are not on your favorite
toys list?
You have two toy boxes: MyToys and FriendsToys . Both have a toy_name column.
You want to find all toys that are in MyToys but not in FriendsToys . How would you
do this using a LEFT JOIN ?
You have a toy box ToySizes with toy_name and size . You want to find the toy with
the largest size, but if there are two toys with the same largest size, you want to pick
the one that comes first alphabetically. How would you do this using ORDER BY and
LIMIT (or TOP )?
You have a toy box ToySales with toy_name , color , and sales_amount . You want to
find the total sales_amount for each color , but only for colors that have a total
sales_amount greater than 100. How would you write this query?
You have a toy box ToyPrices with toy_name and price . You want to find all toys
whose price is higher than the average price of all toys, but only for toys that are also
more expensive than the cheapest toy. How would you use subqueries to solve this?
You have a toy box ToyScores with toy_name and score . You want to rank the toys
by their score from highest to lowest. If two toys have the same score, they should
get the same rank, and the next rank should not skip a number. Which window
function would you use and how?
You have a toy box ToyFeatures with toy_id , toy_name , and feature . You want to
find pairs of toys that share at least one common feature but are not the same toy.
How would you use a SELF JOIN to find these pairs?
You have a toy box ToyStatus with toy_name and status (e.g., 'broken', 'new',
'used'). You want to count how many toys are 'new' and how many are 'broken' in a
single query, showing both counts as separate columns. How would you use a CASE
statement within an aggregation to do this?
Question 9: The Time-Traveling Toy
You have a toy box ToyDates with toy_name and purchase_date . You want to find
out what date it will be exactly 30 days after each purchase_date . Which SQL function
would help you with this?
You have a complex query that joins three tables ( Toys , Owners , Stores ) to show
toy_name , owner_name , and store_name . You use this query very often. How can you
save this complex query so you can use it easily later, as if it were a simple table? What
is this SQL object called?
SELECT M.toy_name
FROM MyToys M
LEFT JOIN FriendsToys F ON M.toy_name = F.toy_name
WHERE F.toy_name IS NULL;
SELECT
SUM(CASE WHEN status = 'new' THEN 1 ELSE 0 END) AS NewToysCount,
SUM(CASE WHEN status = 'broken' THEN 1 ELSE 0 END) AS BrokenToysCount
FROM ToyStatus;