SELECT and FROM Basics
Progress Tracking
Log in to save this lesson and continue from where you left off.
Being Specific About What You Want
In the last lesson, you learned that SELECT tells the database which columns to return. Simple enough. But there's more nuance here than you might expect, and getting it right matters for both performance and readability.
Why SELECT * is a Bad Habit
When you're exploring a new table, SELECT * is fine. It shows you everything, which helps you understand what you're working with.
SELECT * FROM techcorp_workforce;But in real work — queries that run in dashboards, reports, or production systems — SELECT * causes problems:
- Performance — you're pulling data you don't need. On big tables, this slows everything down.
- Clarity — someone reading your query can't tell what data actually matters.
- Fragility — if someone adds a column to the table, your query's output changes unexpectedly.
Get in the habit of specifying columns:
-- Instead of SELECT *, specify what you need:
SELECT
id,
first_name,
last_name,
department
FROM techcorp_workforce;Choosing Column Order
SELECT
order_details,
cust_id,
total_order_cost
FROM orders;| id | first_name | last_name | department | salary | phone_number | joining_date |
|---|---|---|---|---|---|---|
| 1 | Sarah | Mitchell | HR | 95000 | 555-0101 | 2021-03-15 |
| 2 | Michael | Chen | HR | 88000 | 555-0102 | 2022-06-01 |
| 3 | Emily | Rodriguez | HR | 82500 | 2021-09-20 | |
| 4 | David | Park | HR | 80000 | 555-0104 | 2023-01-10 |
| 5 | Lisa | Thompson | HR | 65000 | 2021-04-05 |
Select department, first name, and salary from `techcorp_workforce` — in that order.
This seems trivial, but it matters when you're building reports or exporting data. Put the most important columns first.
Renaming Columns with Aliases
Database column names like employee_id or created_at make sense for developers. They're consistent, predictable, and avoid spaces or special characters. But when you're building a report or dashboard for stakeholders, you want something more readable.
That's what aliases are for. Use AS to rename a column in your output:
Rewrite the query using AS to give salary the alias `annual_pay` and department the alias `dept`.
Use double quotes around aliases that contain spaces or special characters. Single-word aliases don't need quotes: joining_date AS start_date works fine.
When Aliases Are Required
Aliases aren't just cosmetic. Sometimes you need them. When you create a calculated column, it has no name until you give it one.
Add a monthly salary column by dividing each employee's annual salary by 12 and giving it a clear label.
Basic Arithmetic in SELECT
SQL supports standard math operators directly in your SELECT clause:
+addition — example:salary + 5000adds a bonus-subtraction — example:salary - taxcalculates net pay*multiplication — example:price * quantitygets a total/division — example:salary / 12converts annual to monthly
We added a calculated column showing each employee's 10% bonus, now you add a fourth column showing their total salary including that bonus.
Calculated columns only exist in your query results — they don't modify anything stored in the table.
If salary is stored as an integer, salary / 12 may truncate decimals. For precise results in PostgreSQL, cast first: salary::numeric / 12.
Combining Text with Concatenation
Sometimes you need to combine text from multiple columns — for example, creating a full name from first_name and last_name.
String Concatenation
SELECT
CONCAT(first_name, ' ', last_name) AS full_name
FROM employees;Select full name (first and last with a space) and department from `techcorp_workforce`.
PostgreSQL and Oracle also support || for concatenation (first_name || ' ' || last_name). CONCAT() is more portable across dialects.
The AS Keyword is Optional (But Use It Anyway)
SQL lets you skip the AS keyword:
SELECT
first_name "First Name"
FROM techcorp_workforce;This works, but it's harder to read. The explicit AS makes your intent clear. Don't skip it.
Removing Duplicates with DISTINCT
Sometimes you want to know what values exist in a column, not see every row. SELECT DISTINCT removes duplicate values from your results.
Let's look at the orders table:
| id | cust_id | order_date | order_details | total_order_cost |
|---|---|---|---|---|
| 1 | 3 | 2019-03-04 | Coat | 100 |
| 2 | 3 | 2019-03-01 | Shoes | 80 |
| 3 | 3 | 2019-03-07 | Skirt | 30 |
| 4 | 7 | 2019-02-01 | Coat | 25 |
| 5 | 7 | 2019-03-10 | Shoes | 80 |
Without DISTINCT, you'd see duplicate order details:
Select just the `order_details` column from the `orders` table.
Update the query to return only unique order details with SELECT DISTINCT.
DISTINCT with Multiple Columns
When you use DISTINCT with multiple columns, it removes rows where the entire combination is duplicated:
Select the unique combinations of `customer_id` and `order_details` from `orders`.
This returns unique customer-product pairs. So if customer 3 ordered Shoes twice, you'd only see that combination once.
DISTINCT applies to the entire row, not just the first column. This trips people up sometimes.
A Quick Note on Data Types
Every column in a database has a data type. You don't need to memorize these, but it helps to know the main categories:
- Text —
VARCHAR,TEXT,CHAR— used for names, emails, descriptions - Numbers —
INTEGER,DECIMAL,FLOAT— used for counts, amounts, percentages - Dates —
DATE,TIMESTAMP,DATETIME— used for when things happened - Boolean —
TRUE/FALSE— used for yes/no flags
Why does this matter? Because you can't do math on text, and you can't search for patterns in numbers (well, you can, but you shouldn't). Understanding data types helps you avoid weird errors and choose the right functions.
We'll cover type-specific operations in later modules. For now, just know that the database handles different data types differently.
Practice: Selecting Columns with Aliases
Let's practice with the restaurant inspections data:
| serial_number | activity_date | facility_name | score | grade | service_code | service_description | employee_id | facility_address | facility_city | facility_id | facility_state | facility_zip | owner_id | owner_name | pe_description | program_element_pe | program_name | program_status | record_id |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| DAQHRSETQ | 2017-06-08 | MARGARITAS CAFE | 93 | A | 1 | ROUTINE INSPECTION | EE0000006 | 5026 S CRENSHAW BLVD | LOS ANGELES | FA0023656 | CA | 90043 | OW0004133 | BAZAN, ASCENCION | RESTAURANT (61-150) SEATS HIGH RISK | 1638 | MARGARITAS CAFE | ACTIVE | PR0011718 |
| DA2GQRJOS | 2017-03-07 | LAS MOLENDERAS | 97 | A | 1 | ROUTINE INSPECTION | EE0000997 | 2635 WHITTIER BLVD | LOS ANGELES | FA0160416 | CA | 90023 | OW0125379 | MARISOL FEREGRINO | RESTAURANT (0-30) SEATS HIGH RISK | 1632 | LAS MOLENDERAS | INACTIVE | PR0148504 |
| DAMQTA46T | 2016-03-22 | SANDRA'S TAMALES | 93 | A | 1 | ROUTINE INSPECTION | EE0001049 | 5390 WHITTIER BLVD | LOS ANGELES | FA0171769 | CA | 90022-4032 | OW0178828 | SANDRA'S TAMALES INC. | RESTAURANT (0-30) SEATS MODERATE RISK | 1631 | SANDRA'S TAMALES | ACTIVE | PR0164225 |
| DAXMBTIRZ | 2018-02-12 | CAFE GRATITUDE | 97 | A | 1 | ROUTINE INSPECTION | EE0000828 | 639 N LARCHMONT BLVD STE #102 | LOS ANGELES | FA0058921 | CA | 90004 | OW0005704 | CAFE GRATITUDE LARCHMONT LLC | RESTAURANT (61-150) SEATS HIGH RISK | 1638 | CAFE GRATITUDE | ACTIVE | PR0019854 |
| DAK8TBMS0 | 2015-09-10 | THE WAFFLE | 90 | A | 1 | ROUTINE INSPECTION | EE0000709 | 6255 W SUNSET BLVD STE #105 | LOS ANGELES | FA0051830 | CA | 90028 | OW0035796 | THE WAFFLE, LLC | RESTAURANT (61-150) SEATS HIGH RISK | 1638 | THE WAFFLE | ACTIVE | PR0010922 |
Find the facility name, owner name, and inspection score. Label the score column as `Inspection Score`.
Common Mistakes
Forgetting the comma between columns
-- This will give an error:
SELECT
first_name
last_name
FROM techcorp_workforce;
-- SQL thinks you're aliasing first_name as "last_name"
-- What you meant:
SELECT
first_name,
last_name
FROM techcorp_workforce;Trailing comma after the last column
-- This will give an error:
SELECT
first_name,
last_name, -- extra comma
FROM techcorp_workforce;
-- Correct:
SELECT
first_name,
last_name
FROM techcorp_workforce;Misspelling column names
SQL won't guess what you meant. If the column is first_name and you type firstname, you'll get an error. Check your spelling, and remember that most databases are case-sensitive for column names.
Key Takeaways
- Specify columns instead of using
SELECT *in production queries. - Column order in
SELECTdetermines output order. - Use
ASto create readable column aliases — always write it explicitly. DISTINCTremoves duplicate rows from results — it applies to the entire row, not just the first column.- Data types determine what operations you can perform on columns.
What's Next
Now you know how to get data out of a table. But so far, you're getting all rows. In the next lesson, you'll learn to filter data with WHERE — which is when SQL starts to feel actually powerful.