SQL SELECT Statement
SELECT is the SQL statement you will write more than any other. It reads rows from a table and returns only the columns you ask for. In this lesson every query runs on a real MySQL 8.4 server, and you see the table it reads, the result it returns and what happens at each step.
- Read specific columns, or every column with
SELECT * - Calculate new columns such as yearly salary
- Understand the order in which MySQL runs a query
- Avoid the most common SELECT mistakes
What does SELECT do?
A database stores data in tables: rows and columns, like a spreadsheet. SELECT asks the database a question and gets a result set back, which is also a table. It never changes the stored data, so it is always safe to run.
Every query in this lesson reads the employees table of our sample company database. Here are the columns we use:
| emp_id | first_name | last_name | job_title | salary | city |
|---|---|---|---|---|---|
| 100 | Meera | Kapoor | CEO | 250000 | Mumbai |
| 101 | Asha | Rao | Engineering Manager | 125000 | Bengaluru |
| 102 | Rahul | Mehta | Senior Developer | 98000 | Bengaluru |
| 103 | Priya | Nair | QA Engineer | 72000 | Pune |
| 104 | Karan | Shah | Developer | 72000 | Bengaluru |
| 105 | Vikram | Singh | Sales Manager | 105000 | Mumbai |
| 106 | Neha | Gupta | Sales Executive | 54000 | Mumbai |
| 107 | Arjun | Das | Sales Executive | 48000 | Kolkata |
| 108 | Kavya | Iyer | Marketing Lead | 88000 | Pune |
| 109 | Rohan | Joshi | Content Writer | 45000 | Pune |
| 110 | Sneha | Kulkarni | HR Manager | 78000 | Delhi |
| 111 | Amit | Verma | Intern | 25000 | Bengaluru |
SELECT syntax
SELECT column1, column2, ...FROM table_name;SELECTlists the columns you want, separated by commas.FROMnames the table to read.- The semicolon
;ends the statement. MySQL needs it when you send several statements together.
Select specific columns
Show each employee’s first name and job title:
SELECT first_name, job_titleFROM employees;| first_name | job_title |
|---|---|
| Meera | CEO |
| Asha | Engineering Manager |
| Rahul | Senior Developer |
| Priya | QA Engineer |
| Karan | Developer |
| Vikram | Sales Manager |
| Neha | Sales Executive |
| Arjun | Sales Executive |
| Kavya | Marketing Lead |
| Rohan | Content Writer |
| Sneha | HR Manager |
| Amit | Intern |
FROM employeesruns first: MySQL opens theemployeestable and takes all 12 rows.SELECT first_name, job_titlekeeps only those two columns and drops the rest.- The columns appear in the order you listed them, not the order they have in the table.
- There is no
WHERE, so every row comes back: 12 rows in set.
Click Try it, change the column list (for example add salary), and press Run. The query runs in your browser on a copy of the same table.
Select all columns with SELECT *
The asterisk * means “every column, in table order”:
SELECT * FROM employees;| emp_id | first_name | last_name | dept_id | manager_id | job_title | salary | commission | hire_date | city |
|---|---|---|---|---|---|---|---|---|---|
| 100 | Meera | Kapoor | NULL | NULL | CEO | 250000 | NULL | 2015-01-05 | Mumbai |
| 101 | Asha | Rao | 1 | 100 | Engineering Manager | 125000 | NULL | 2018-04-12 | Bengaluru |
| 102 | Rahul | Mehta | 1 | 101 | Senior Developer | 98000 | NULL | 2019-07-01 | Bengaluru |
| 103 | Priya | Nair | 1 | 101 | QA Engineer | 72000 | NULL | 2021-01-18 | Pune |
| 104 | Karan | Shah | 1 | 102 | Developer | 72000 | NULL | 2022-08-29 | Bengaluru |
| 105 | Vikram | Singh | 2 | 100 | Sales Manager | 105000 | 12000 | 2017-11-20 | Mumbai |
| 106 | Neha | Gupta | 2 | 105 | Sales Executive | 54000 | 6000 | 2022-03-14 | Mumbai |
| 107 | Arjun | Das | 2 | 105 | Sales Executive | 48000 | 4500 | 2023-06-05 | Kolkata |
| 108 | Kavya | Iyer | 3 | 100 | Marketing Lead | 88000 | NULL | 2020-09-09 | Pune |
| 109 | Rohan | Joshi | 3 | 108 | Content Writer | 45000 | NULL | 2024-01-22 | Pune |
| 110 | Sneha | Kulkarni | 4 | 100 | HR Manager | 78000 | NULL | 2019-02-25 | Delhi |
| 111 | Amit | Verma | 1 | 101 | Intern | 25000 | NULL | 2025-06-02 | Bengaluru |
FROM employeesreads all 12 rows.*expands to all 10 columns:emp_id, first_name, last_name, dept_id, manager_id, job_title, salary, commission, hire_date, city.- Empty values show as
NULL. Only the three sales staff have acommission, and the CEO has nodept_idormanager_id.
SELECT * is fine for exploring a table, but avoid it in application code and reports. It sends columns you do not need, makes queries slower on wide tables, and breaks code silently when someone adds or reorders a column.
Calculated columns and aliases
A column in the SELECT list can be an expression. MySQL calculates it for every row. Use AS to give it a readable name (an alias):
SELECT first_name, salary, salary * 12 AS yearly_salaryFROM employees;| first_name | salary | yearly_salary |
|---|---|---|
| Meera | 250000 | 3000000 |
| Asha | 125000 | 1500000 |
| Rahul | 98000 | 1176000 |
| Priya | 72000 | 864000 |
| Karan | 72000 | 864000 |
| Vikram | 105000 | 1260000 |
| Neha | 54000 | 648000 |
| Arjun | 48000 | 576000 |
| Kavya | 88000 | 1056000 |
| Rohan | 45000 | 540000 |
| Sneha | 78000 | 936000 |
| Amit | 25000 | 300000 |
FROM employeesreads all 12 rows.- For each row, MySQL multiplies that row’s
salaryby 12. AS yearly_salarynames the new column. Without it, the header would be the expression textsalary * 12.- The stored
salaryvalues do not change: the calculation exists only in the result.
You can also join text with CONCAT():
SELECT emp_id, CONCAT(first_name, ' ', last_name) AS full_name, cityFROM employees;| emp_id | full_name | city |
|---|---|---|
| 100 | Meera Kapoor | Mumbai |
| 101 | Asha Rao | Bengaluru |
| 102 | Rahul Mehta | Bengaluru |
| 103 | Priya Nair | Pune |
| 104 | Karan Shah | Bengaluru |
| 105 | Vikram Singh | Mumbai |
| 106 | Neha Gupta | Mumbai |
| 107 | Arjun Das | Kolkata |
| 108 | Kavya Iyer | Pune |
| 109 | Rohan Joshi | Pune |
| 110 | Sneha Kulkarni | Delhi |
| 111 | Amit Verma | Bengaluru |
- For every row,
CONCAT()gluesfirst_name, a space andlast_nameinto one string. - The result column is called
full_namebecause of the alias. emp_idandcityare copied as they are.
SELECT without a table
SELECT can also evaluate expressions without reading any table. That is handy for testing a function before you use it in a real query:
SELECT 7 * 6 AS answer, UPPER('sqatools') AS site, CURDATE() IS NOT NULL AS has_date;| answer | site | has_date |
|---|---|---|
| 42 | SQATOOLS | 1 |
- There is no
FROM, so MySQL evaluates each expression once and returns one row. 7 * 6is 42,UPPER()turns the text to capitals, and a comparison returns1for true.
The order MySQL runs a query
You write a query in one order but MySQL runs it in another. Knowing this explains most beginner errors, such as “unknown column” when you use an alias in WHERE.
| Step | Clause | What happens |
|---|---|---|
| 1 | FROM / JOIN | Pick the tables and combine them |
| 2 | WHERE | Keep only the rows that match the condition |
| 3 | GROUP BY | Put rows into groups |
| 4 | HAVING | Keep only the groups that match |
| 5 | SELECT | Calculate the output columns and aliases |
| 6 | DISTINCT | Remove duplicate rows |
| 7 | ORDER BY | Sort the result |
| 8 | LIMIT | Return only the first N rows |
Because SELECT (step 5) runs after WHERE (step 2), an alias created in SELECT does not exist yet inside WHERE:
SELECT first_name, salary * 12 AS yearly_salaryFROM employeesWHERE yearly_salary > 1000000;ERROR 1054 (42S22): Unknown column 'yearly_salary' in 'where clause'
Common SELECT mistakes
- Missing comma between columns.
SELECT first_name job_title FROM employeesdoes not fail: MySQL readsjob_titleas an alias forfirst_name, so you get one column with the wrong header. - Comma after the last column.
SELECT first_name, FROM employeesis a syntax error. - Quoting column names with single quotes.
SELECT 'salary' FROM employeesreturns the text salary on every row. Write column names without quotes; wrap a name in backticks only when it has spaces or is a reserved word (see SQL Syntax). - Expecting a fixed row order. Without ORDER BY the database may return rows in any order. Never rely on the order you happen to see.
Here is the missing-comma trap in action:
SELECT first_name job_titleFROM employeesLIMIT 3;| job_title |
|---|
| Meera |
| Asha |
| Rahul |
Predict the result
What does this query return? Think about how many columns, and what the header is.
SELECT last_name, salary / 1000 AS salary_kFROM employeesLIMIT 2;| last_name | salary_k |
|---|---|
| Kapoor | 250.0000 |
| Rao | 125.0000 |
Two columns: last_name and salary_k. MySQL’s / always returns a decimal number, so 250000 / 1000 shows as 250.0000. LIMIT 2 keeps the first two rows.
Exercise: List names and cities
Write a query that shows every employee’s emp_id, first_name and city, with city renamed to office.
| emp_id | first_name | office |
|---|---|---|
| 100 | Meera | Mumbai |
| 101 | Asha | Bengaluru |
| 102 | Rahul | Bengaluru |
| 103 | Priya | Pune |
| 104 | Karan | Bengaluru |
| 105 | Vikram | Mumbai |
| 106 | Neha | Mumbai |
| 107 | Arjun | Kolkata |
| 108 | Kavya | Pune |
| 109 | Rohan | Pune |
| 110 | Sneha | Delhi |
| 111 | Amit | Bengaluru |
Hint 1
Put the three columns after SELECT, separated by commas.
Hint 2
Rename a column with AS office.
SELECT emp_id, first_name, city AS officeFROM employees;| emp_id | first_name | office |
|---|---|---|
| 100 | Meera | Mumbai |
| 101 | Asha | Bengaluru |
| 102 | Rahul | Bengaluru |
| 103 | Priya | Pune |
| 104 | Karan | Bengaluru |
| 105 | Vikram | Mumbai |
| 106 | Neha | Mumbai |
| 107 | Arjun | Kolkata |
| 108 | Kavya | Pune |
| 109 | Rohan | Pune |
| 110 | Sneha | Delhi |
| 111 | Amit | Bengaluru |
Exercise: Monthly bonus
Show each employee’s first_name, salary and a column called bonus that is 10% of the salary.
| first_name | salary | bonus |
|---|---|---|
| Meera | 250000 | 25000.00 |
| Asha | 125000 | 12500.00 |
| Rahul | 98000 | 9800.00 |
| Priya | 72000 | 7200.00 |
| Karan | 72000 | 7200.00 |
| Vikram | 105000 | 10500.00 |
| Neha | 54000 | 5400.00 |
| Arjun | 48000 | 4800.00 |
| Kavya | 88000 | 8800.00 |
| Rohan | 45000 | 4500.00 |
| Sneha | 78000 | 7800.00 |
| Amit | 25000 | 2500.00 |
Hint 1
10% of a number is the number multiplied by 0.10.
SELECT first_name, salary, salary * 0.10 AS bonusFROM employees;| first_name | salary | bonus |
|---|---|---|
| Meera | 250000 | 25000.00 |
| Asha | 125000 | 12500.00 |
| Rahul | 98000 | 9800.00 |
| Priya | 72000 | 7200.00 |
| Karan | 72000 | 7200.00 |
| Vikram | 105000 | 10500.00 |
| Neha | 54000 | 5400.00 |
| Arjun | 48000 | 4800.00 |
| Kavya | 88000 | 8800.00 |
| Rohan | 45000 | 4500.00 |
| Sneha | 78000 | 7800.00 |
| Amit | 25000 | 2500.00 |
Quick quiz
1. Which clause does MySQL run first?
MySQL must know which table to read before it can pick columns, so FROM comes first.
2. What does SELECT * return?
* expands to all columns in the order they were defined in CREATE TABLE.
3. You run SELECT first_name job_title FROM employees. What happens?
Without a comma, job_title becomes an alias for first_name.
4. Does SELECT change the data stored in the table?
SELECT is read-only. Use UPDATE to change data.
SELECT FAQ
What is the SELECT statement in SQL?
SELECT is the SQL command that reads data from one or more tables. You list the columns you want after SELECT and the table after FROM, and the database returns a result set.
Is SELECT * bad practice?
It is fine for quick exploration, but in applications and reports list the columns you need. SELECT * transfers extra data and can break code when the table changes.
Can I use an alias from SELECT in the WHERE clause?
No. WHERE runs before SELECT, so the alias does not exist yet. Repeat the expression, or wrap the query in a subquery or CTE. You can use the alias in ORDER BY.
Is SQL case sensitive?
Keywords such as SELECT and FROM are not case sensitive, so select works too. Writing keywords in capitals is a convention that makes queries easier to read. Whether table names are case sensitive depends on the operating system and MySQL settings.
What is the order of execution of a SQL query?
FROM and JOIN, then WHERE, GROUP BY, HAVING, SELECT, DISTINCT, ORDER BY and finally LIMIT.