SELECT Basics
The anatomy of a SELECT statement and how to start reading data.
Every SQL query that reads data starts with SELECT. You will write it hundreds of times before you are done, so it is worth understanding how it actually works - not just the syntax, but the order in which the database evaluates things.
The basic form
SELECT column1, column2
FROM table_name;You name the columns you want, you name the table they live in, and the database returns every row with only those columns included. One thing that surprises people: the database finds the table first, then figures out which columns to return. That matters later when you start writing expressions that reference aliases.
To return every column without naming them, use *:
SELECT *
FROM employees;The asterisk is useful for exploration when you do not know what columns a table has. In production code, name your columns explicitly - it makes your intent clear, avoids surprises when the table gains new columns, and helps the database skip fetching data you do not need.
Aliases
You can rename any column in the output using AS. The alias exists only in the result set and does not change anything about the underlying table.
SELECT
first_name AS name,
salary * 12 AS annual_salary
FROM employees;Without an alias, calculated columns get a header like ?column? or salary * 12 - not great. Aliases fix that. You can also alias tables, which becomes important with joins.
Expressions in SELECT
Column names are just the starting point. You can include any valid expression in SELECT - arithmetic, string operations, function calls, anything.
SELECT
first_name,
last_name,
first_name || ' ' || last_name AS full_name,
salary * 1.10 AS salary_with_raise,
UPPER(department) AS department
FROM employees;The || operator concatenates strings in PostgreSQL. If you come from MySQL, you may know CONCAT() instead - both work, though CONCAT() is more portable across database systems.
Every expression is evaluated per row. When you write salary * 1.10, the database runs that calculation independently for every employee in the result.
DISTINCT
Adding DISTINCT after SELECT removes duplicate rows from the result:
SELECT DISTINCT department
FROM employees;Without DISTINCT, this returns one row per employee, with department names repeated many times over. With DISTINCT, each department appears once. It is a good way to explore what values a column actually contains.
The part that trips people up: DISTINCT applies to the combination of all selected columns, not just the first one.
SELECT DISTINCT department, title
FROM employees;This returns each unique (department, title) pair - not each unique department.
Column order and semicolons
Columns appear in the result in the order you list them, which may differ from how they are stored in the table.
Every SQL statement ends with a semicolon. In most clients, that is what tells the parser where one statement ends and the next begins. Technically optional for a single statement, but build the habit now - missing semicolons cause a specific kind of confusing error that is annoying to debug.
Everything else in SQL is just adding clauses to this basic shape: WHERE to filter rows, ORDER BY to sort, GROUP BY to summarize, JOIN to combine tables. The core of SELECT ... FROM ... never changes. That is the foundation you are building on.