Your First Query — SELECT & FROM
The two most important words in SQL — what they mean, how the database executes them, and every variation you will use in the real world
// Part 01
The Two Words That Run the World's Data
Every piece of data you have ever seen on a screen — your bank balance, your Swiggy order history, your Zerodha portfolio, your Instagram feed — was retrieved from a database using a query that starts with the same two words: SELECT and FROM.
SELECT and FROM are not just beginner syntax that you graduate past. They are the foundation of every SQL query ever written, from the simplest lookup to the most complex analytical pipeline. A senior data engineer at a FAANG company writes SELECT and FROM a hundred times a day. Understanding them deeply — not just mechanically, but knowing what the database actually does when it sees them — makes every SQL concept that follows easier to learn.
Here is the simplest possible SQL query:
Two lines. Two words. This query asks the FreshMart database one question: "Give me the first_name, last_name, and city columns from every row in the customers table." The database reads every row in customers, extracts those three columns, and returns the result. That is all SELECT and FROM do — and they do it for everything from 5 rows to 5 billion rows.
// Part 02
What SELECT and FROM Actually Mean
FROM — tell the database where to look
FROM is actually executed before SELECT, even though it is written after it. The database reads FROM first and identifies which table (or tables) to work with. FROM is the source — it tells the database where to find the data.
Think of FROM as walking into the right filing cabinet. If you need customer information, you go to the customers drawer. If you need order information, you go to the orders drawer. You declare this in FROM. Everything else in the query operates on whatever FROM points at.
SELECT — tell the database what to return
After FROM identifies the table, SELECT specifies which columns from that table to include in the result. SELECT is a projection — it narrows the output from all available columns to only the ones you asked for. A table might have 10 columns. SELECT lets you return 1, 3, or all 10 — your choice, every query.
The order SQL is written vs the order it is executed
This is one of the most important things to understand early. SQL queries are written in a specific order that does not match how the database executes them. Many confusing errors and surprising results come from misunderstanding this.
| Written order | Execution order | What happens |
|---|---|---|
| 1. SELECT | 2. Executed second | Choose which columns to return from the already-identified rows |
| 2. FROM | 1. Executed first | Identify the table — this always runs before SELECT |
| 3. WHERE | 3. Executed third | Filter rows (you will learn this in Module 06) |
| 4. GROUP BY | 4. Executed fourth | Group filtered rows (Module 28) |
| 5. HAVING | 5. Executed fifth | Filter groups (Module 29) |
| 6. ORDER BY | 6. Executed sixth | Sort the result (Module 08) |
| 7. LIMIT | 7. Executed last | Cut to n rows (Module 09) |
The key insight for now: FROM runs before SELECT. The database first decides which table to read, then decides which columns from that table to return. Every clause you add in future modules fits somewhere in this execution order.
// Part 03
SELECT * — The Wildcard and Why to Use It Carefully
The asterisk * in SELECT means "all columns." Instead of listing every column by name, you use * to tell the database to return everything in the table.
SELECT * is extremely useful for exploration — when you join a new project and want to see what a table contains, SELECT * LIMIT 10 is the first query you run. It shows you every column, every data type, and the shape of the data instantly.
Why SELECT * is dangerous in production code
In production queries — queries that run inside applications, dashboards, or data pipelines — SELECT * is almost always the wrong choice. Here is why.
It retrieves unnecessary data. If the customers table has 10 columns but your application only needs first_name and email, SELECT * fetches all 10 columns, transfers them over the network, and forces the application to discard 8 of them. At 10 million rows this wastes significant time and bandwidth.
It breaks when the schema changes. If someone adds a new column to the customers table next month, your SELECT * query suddenly returns an extra column. Any code that expects a specific number or order of columns silently breaks. Explicit column names make your query immune to schema additions.
It prevents index optimisation. The database has a performance optimisation called a covering index — if your SELECT only asks for columns that exist in an index, the database can serve the query entirely from the index without reading the main table. SELECT * prevents this optimisation because * includes columns that are not in the index.
// Part 04
Selecting Specific Columns — The Right Way
When you name specific columns in SELECT, you are being explicit about exactly what you need. The database returns only those columns, in exactly the order you listed them — not necessarily the order they exist in the table.
Column order in SELECT is yours to control
The columns in your result appear in the order you list them in SELECT — not the order they are defined in the table. In the query above, city appears first even though it is the 6th column in the customers table. This lets you organise results in whatever order makes sense for the person reading them.
Selecting columns from FreshMart — practical examples
// Part 05
SELECT with Calculations — Using SQL as a Calculator
SELECT does not just return column values as they are stored. It can perform calculations on those values — arithmetic, string operations, date math — and return the computed result as a new column in the output. The table itself is never changed. The calculation happens at query time and exists only in the result.
Arithmetic in SELECT
Several things to notice here. First, the arithmetic operators: + (add), - (subtract), * (multiply), / (divide). Second, the AS keyword — it gives the computed column a name in the result. Without AS, the database would show the raw expression as the column header. Third, ROUND(value, decimal_places) — a built-in function that rounds to a specified number of decimal places. You will learn all built-in functions in Modules 41–44.
Calculating with dates
Combining text columns
// Part 06
SELECT with Literal Values — Returning Constants
SELECT does not have to return columns from a table at all. You can SELECT literal values — fixed strings, numbers, or the result of functions — and the database returns them directly. This is more useful than it sounds.
Selecting literals is used in practice for: adding a constant label to identify the source of data when combining results from multiple queries, computing values that do not depend on any specific row (like a tax rate or a fixed fee), and testing expressions before embedding them in a larger query.
// Part 07
Case Sensitivity — What SQL Cares About and What It Does Not
SQL beginners are often confused about when capitalisation matters. The rule is simple once you know it:
SQL keywords are case-insensitive. SELECT, select, Select, and SeLeCt are all identical to the database. FROM, from, From — all the same. The convention is to write keywords in UPPERCASE — it makes queries easier to read by visually separating your instructions from your data. All examples in this course follow this convention.
Table and column names depend on the database. In PostgreSQL, table and column names are case-insensitive unless you quote them with double quotes. In MySQL, table names are case-sensitive on Linux (because file names are case-sensitive on Linux) but case-insensitive on Windows. The safest practice: always use lowercase for table and column names (as FreshMart does) and write them the same way every time.
String values are case-sensitive. The value 'Bangalore' is not the same as 'bangalore' or 'BANGALORE' in a WHERE clause. String comparisons respect exact case — you will see this in Module 06 when learning WHERE.
// Part 08
Comments in SQL — Explaining Your Queries
SQL supports two types of comments. Comments are ignored by the database — they exist only for humans reading the query. Writing good comments is a professional habit that makes your queries easier to understand, debug, and maintain.
When to write comments in SQL: when a calculation is non-obvious (explain the formula), when a column name is ambiguous (clarify what it means in this context), when a query has a non-obvious filter or business rule (explain why), and when you are sharing a query with teammates who will need to understand it without asking you.
🎯 Pro Tip
The best SQL queries at Indian tech companies read like a story. The table name tells you what you are looking at, the column names tell you what you are measuring, and comments explain the why — the business rule or decision behind each non-obvious choice. A query you write today needs to be understandable by your colleague six months from now without your explanation.
// Part 09
SELECT DISTINCT — Removing Duplicate Rows
By default, SELECT returns every row from the table — including duplicates. If you want only unique values, use SELECT DISTINCT. The database returns each unique combination of the columns you selected, once.
DISTINCT is useful for: finding all unique values in a column (all cities FreshMart serves, all product categories, all payment methods used), checking what values actually exist in a column before filtering on them, and understanding the cardinality of a column — how many distinct values it has.
// Part 10
Formatting Your Queries — The Professional Standard
SQL does not care about whitespace, line breaks, or indentation. These two queries are identical to the database:
The formatted version takes more lines but is dramatically easier to read, modify, debug, and review. The professional SQL formatting conventions used throughout this course — and at most Indian tech companies:
SELECT, FROM, WHERE, JOIN
SELECT first_name, last_name,
first_name, last_name,
SELECT ... FROM ... WHERE ...
unit_price - cost_price AS margin
FROM customers;
// Part 11
Complete FreshMart Examples — Real Business Questions
Now let us put everything together. Here are real business questions that FreshMart's management team might ask, answered with SELECT and FROM alone — no filtering, no aggregation, just reading the right columns from the right table.
// Part 12
What This Looks Like at Work
You are three weeks into your job as a Business Analyst at a Bangalore fintech startup. Your manager, Deepika, sends a Slack message on a Tuesday morning.
Deepika (Manager): Hey — can you pull the current list of all active merchants? I just need their merchant_id, business_name, city, and onboarded_date. Nothing fancy, just the raw list. Google Sheet is fine. Needed before the 3pm call.
🎯 Pro Tip
The first query you run on any unfamiliar table should always be SELECT * FROM table_name LIMIT 10. This shows you the column names, the data types, sample values, and how the data is formatted — all the information you need to write the proper query. Never guess column names. Always check first.
// Part 13
Interview Prep — 5 Questions With Complete Answers
SELECT * retrieves all columns from the specified table in their defined order. Selecting specific columns — SELECT col1, col2, col3 — retrieves only the named columns in the order you specify. The data returned is a subset of what SELECT * would return, and the columns appear in your chosen order regardless of their order in the table definition.
SELECT * is appropriate for exploration — when you want to see what a table contains or are debugging a data issue. In production code it has three significant problems. First, it retrieves unnecessary data — if your application needs 2 columns but SELECT * fetches 15, you waste network bandwidth and memory on every execution. Second, it breaks silently when schema changes — if a column is added or removed, code that expects specific columns at specific positions will produce incorrect results with no error. Third, it prevents covering index optimisation — the database cannot serve the query from an index alone if you ask for all columns.
The professional rule: use SELECT * only in interactive exploration and debugging. Every query that runs in an application, a scheduled job, a dashboard, or a data pipeline should name its columns explicitly.
The written order of a SQL query (SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT) does not match the execution order. The database executes clauses in this sequence: FROM first (identify the source table or tables), WHERE second (filter individual rows), GROUP BY third (group the filtered rows), HAVING fourth (filter the groups), SELECT fifth (compute the output columns from the remaining rows), ORDER BY sixth (sort the result), LIMIT last (cut to the specified number of rows).
This execution order has practical consequences. It explains why you cannot use a SELECT alias in a WHERE clause — WHERE runs before SELECT, so the alias does not exist yet when WHERE is evaluated. It explains why you can use a SELECT alias in ORDER BY — ORDER BY runs after SELECT. It explains why aggregate functions like COUNT() and SUM() appear in SELECT and HAVING but not in WHERE — WHERE runs before grouping, so aggregate values do not exist yet at that point.
Understanding execution order also helps with query optimisation. WHERE filtering happens early (before SELECT projection), so effective WHERE conditions reduce the number of rows processed by all subsequent steps. Applying filters as early as possible — through WHERE conditions on indexed columns — is one of the most impactful query performance improvements you can make.
SELECT DISTINCT returns only unique rows — it eliminates duplicate rows from the result set. When you list multiple columns, DISTINCT applies to the combination: every unique combination of the listed columns appears exactly once in the output. SELECT DISTINCT city returns each city once. SELECT DISTINCT city, loyalty_tier returns each unique city-tier pair once.
DISTINCT is appropriate when you genuinely need unique values — finding all distinct cities a company has customers in, all distinct product categories, all distinct payment methods used. It is also useful for data profiling: DISTINCT shows you what values actually exist in a column, which is valuable when exploring a new database.
DISTINCT should be avoided when you do not actually need unique values, because it carries a performance cost — the database must sort or hash all rows to identify and eliminate duplicates. On large tables this can be significantly slower than a plain SELECT. A common mistake is using SELECT DISTINCT to work around a query that returns more rows than expected — this hides an underlying JOIN or filter bug rather than fixing it. The correct fix is to identify why duplicates are appearing (usually a many-to-one JOIN) and address the root cause.
Yes. SELECT can perform arithmetic, string operations, date calculations, and function calls on column values, and return the computed result as a new column in the output. The original table is never modified — calculations happen during query execution and exist only in the result set.
Arithmetic examples: unit_price - cost_price computes the profit margin per product. total_amount * 1.18 applies 18% GST to an order total. quantity * unit_price recalculates the line total. These use the standard arithmetic operators: + (add), - (subtract), * (multiply), / (divide), % (modulo). Division between integers produces an integer in some databases — use CAST or decimal literals if you need decimal division.
String operation example: first_name || ' ' || last_name concatenates first and last name with a space (PostgreSQL/DuckDB syntax). MySQL uses CONCAT(first_name, ' ', last_name). Date example: delivery_date - order_date returns the number of days between two dates in PostgreSQL. Built-in function example: ROUND(price * 0.18, 2) rounds a calculated tax value to 2 decimal places. All computed columns can be given a readable name using AS: unit_price - cost_price AS profit. Without AS, the column header in the result shows the raw expression.
SQL comments are text in a query that the database engine ignores completely — they exist only for humans reading the query. There are two comment syntaxes. Single-line comments start with two hyphens (--) and everything after them on that line is ignored. Multi-line comments start with /* and end with */ and can span any number of lines.
Comments serve four practical purposes in professional SQL work. First, explanation: a non-obvious calculation or filter needs an explanation of the business rule behind it — WHY you are multiplying by 1.18, not just WHAT the multiplication does. Second, attribution: who wrote the query and when, especially in shared query libraries. Third, toggling: commenting out individual SELECT columns or WHERE conditions is easier than deleting and retyping them when debugging. Fourth, documentation: queries in a data pipeline or scheduled job should have a comment explaining what business question they answer and which team owns them.
The mark of a professional SQL writer is queries that read like documentation — the structure tells you what, the comments tell you why. A query you write today at 10 AM should be fully understandable to a colleague at 3 PM without your explanation. This becomes increasingly important as companies grow and queries are shared across teams and maintained over years.
// Part 14
Errors You Will Hit — And Exactly Why They Happen
🎯 Key Takeaways
- ✓SELECT specifies which columns to return. FROM specifies which table to read from. These two keywords are in every SQL query ever written.
- ✓The database executes FROM before SELECT, even though SELECT is written first. Execution order: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT.
- ✓SELECT * returns all columns and is useful for exploration. In production code always name specific columns — SELECT * wastes bandwidth, breaks when schemas change, and prevents covering index optimisation.
- ✓Columns in the result appear in the order you list them in SELECT — not the order they exist in the table.
- ✓SELECT can perform calculations: arithmetic (+ - * /), string operations (|| or CONCAT), date math, and built-in functions. The table is never changed — calculations exist only in the query result.
- ✓Give computed columns a readable name using the AS keyword: unit_price - cost_price AS profit. Without AS, the column header shows the raw expression.
- ✓SELECT DISTINCT eliminates duplicate rows from the result. It applies to the combination of all listed columns. It has a performance cost — only use it when you genuinely need unique values.
- ✓SQL keywords (SELECT, FROM) are case-insensitive. Column and table names are case-insensitive in most databases but exact-match in others. String values in WHERE clauses are always case-sensitive.
- ✓Comment your queries: -- for single-line, /* */ for multi-line. Explain the why, not just the what. Professional queries read like documentation.
- ✓First query on any unfamiliar table: SELECT * FROM table_name LIMIT 10 — see the column names, data types, and sample values before writing the real query.
What comes next
In Module 06, you add the WHERE clause — the most powerful tool for getting only the rows you actually need. This is where SQL goes from "show me everything" to "show me exactly what I asked for." Every filter you will ever write starts here.
Module 06 → Filtering Rows — WHERE ClauseDiscussion
0Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.