A column alias in PostgreSQL assigns a temporary display name to a column or expression in the SELECT list. The alias exists only for the duration of the query — it is not stored in the database, does not rename any table column, and has no effect on the underlying data.
Syntax
SELECT column_name AS alias_name
FROM table_name;
The AS keyword is optional. Both of the following are valid and equivalent:
SELECT unit_price AS price FROM products;
SELECT unit_price price FROM products;
You can alias any expression, not just bare column references:
SELECT expression AS alias_name
FROM table_name;
When an alias contains spaces or special characters, wrap it in double quotes:
SELECT unit_price * stock_qty AS "inventory value"
FROM products;
Practical Example
Create a sample order table and use aliases to produce readable output:
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
reference VARCHAR(20) NOT NULL UNIQUE,
customer_id INT NOT NULL,
subtotal NUMERIC(10, 2) NOT NULL,
tax_rate NUMERIC(5, 4) NOT NULL DEFAULT 0.08,
placed_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
INSERT INTO orders (reference, customer_id, subtotal, tax_rate) VALUES
('ORD-1001', 42, 129.99, 0.08),
('ORD-1002', 17, 49.50, 0.10),
('ORD-1003', 99, 310.00, 0.08),
('ORD-1004', 42, 22.75, 0.05);
Rename a column heading:
SELECT reference AS order_ref, placed_at AS ordered_on
FROM orders;
Result headings change from reference / placed_at to order_ref / ordered_on.
Alias a computed expression:
Without an alias, PostgreSQL labels computed columns with ?column?:
-- Unhelpful heading: ?column?
SELECT reference, subtotal * (1 + tax_rate)
FROM orders;
Add an alias for a meaningful heading:
SELECT
reference,
subtotal,
tax_rate,
subtotal * (1 + tax_rate) AS total_with_tax
FROM orders
ORDER BY total_with_tax DESC;
Use an alias in ORDER BY:
Because ORDER BY is evaluated after SELECT, you can reference the alias:
SELECT
reference,
EXTRACT(EPOCH FROM (now() - placed_at)) / 3600 AS hours_since_order
FROM orders
ORDER BY hours_since_order DESC;
Inspect output column names:
-- Use psql \g or \x to see column names in vertical format
SELECT reference AS order_ref, subtotal AS amount FROM orders LIMIT 1;
Where Aliases Can and Cannot Be Used
| Clause | Alias available? | Reason |
|---|---|---|
ORDER BY | Yes | Evaluated after SELECT |
GROUP BY | Partially (non-standard) | PostgreSQL extension; avoid for portability |
HAVING | No | Evaluated before SELECT |
WHERE | No | Evaluated before SELECT |
| Subquery outer query | Yes | The subquery result is a derived table with the alias as its column name |
Workaround when you need a computed alias in WHERE: wrap the query in a subquery or CTE:
-- Use a subquery to filter on a computed alias
SELECT *
FROM (
SELECT reference, subtotal * (1 + tax_rate) AS total_with_tax
FROM orders
) t
WHERE total_with_tax > 100;
Testing with Vela
When refactoring queries to use aliases — for example, renaming output columns to match a new API contract — use Vela’s database branching to test the change against a production-like copy before rolling it out. Create a branch, run the updated queries, verify that application code consuming the renamed columns behaves correctly in your CI environment, and then promote the change to production with confidence.
Production Tips
- Always include
ASexplicitly even though it is optional — it signals intent and makes diffs easier to review. - Use snake_case aliases to match PostgreSQL’s native identifier casing (
total_with_tax, notTotalWithTax) — unquoted identifiers are folded to lowercase. - Wrap aliases with spaces or special characters in double quotes; avoid them in application-facing column names to reduce quoting overhead in downstream code.
- Do not shadow existing column names with aliases unless intentional — it can cause confusion when queries are nested as subqueries.
- In ORM-generated queries or reporting tools that read column names programmatically, consistent alias naming across queries prevents field-mapping bugs.
- If an alias is defined in a
SELECTand you need it inHAVING, wrap the query in a subquery or use a CTE rather than repeating the expression multiple times.