Table of Contents
- What Are Functions and Operators?
- Core Operators in PostgreSQL
- Essential Built-In Functions
- Advanced Functions
- Practical Examples: Putting It All Together
- Best Practices for Using Functions and Operators
- Conclusion
- References
What Are Functions and Operators?
Before diving in, let’s clarify the basics:
- Operators are symbols or keywords that perform operations on one or more values (operands). For example,
+(addition) or=(equality check). - Functions are reusable blocks of code that take input (arguments) and return a value. They are called by name, e.g.,
SUM(amount)orUPPER(name).
PostgreSQL provides hundreds of operators and functions tailored to different data types (numbers, strings, dates, JSON, arrays, etc.). They are optimized for performance, so using them often leads to faster queries than writing custom logic.
Core Operators in PostgreSQL
Operators are the building blocks of SQL queries. Let’s explore the most common types:
Arithmetic Operators
Used to perform mathematical calculations on numeric values (integers, decimals, etc.).
| Operator | Description | Example | Result |
|---|---|---|---|
+ | Addition | 5 + 3 | 8 |
- | Subtraction | 10 - 4 | 6 |
* | Multiplication | 6 * 7 | 42 |
/ | Division | 20 / 4 | 5 |
% | Modulus (remainder) | 15 % 4 | 3 |
^ | Exponentiation | 2 ^ 3 | 8 |
Example with a table: Suppose we have a sales table with a column amount (sale value). To calculate the total after a 10% tax:
SELECT amount, amount * 1.1 AS total_with_tax
FROM sales;
Comparison Operators
Used to compare values and return TRUE, FALSE, or NULL (if one operand is NULL).
| Operator | Description | Example |
|---|---|---|
= | Equal to | amount = 100 |
!=/<> | Not equal to | product != 'Laptop' |
< | Less than | sale_date < '2023-01-01' |
> | Greater than | amount > 500 |
<= | Less than or equal to | quantity <= 10 |
>= | Greater than or equal to | rating >= 4.5 |
BETWEEN | Between two values (inclusive) | amount BETWEEN 100 AND 500 |
IN | Matches any value in a list | product IN ('Laptop', 'Phone') |
LIKE | Pattern match (case-insensitive by default) | customer_name LIKE 'A%' (names starting with “A”) |
ILIKE | Case-insensitive pattern match (PostgreSQL-specific) | product ILIKE 'laptop' |
Example: Find sales of laptops or phones with amounts between $100 and $500:
SELECT *
FROM sales
WHERE product IN ('Laptop', 'Phone')
AND amount BETWEEN 100 AND 500;
Logical Operators
Combine multiple conditions in WHERE clauses.
| Operator | Description | Example |
|---|---|---|
AND | Both conditions must be true | amount > 100 AND product = 'Laptop' |
OR | At least one condition is true | product = 'Laptop' OR product = 'Phone' |
NOT | Negates a condition | NOT (amount < 100) (amount ≥ 100) |
Example: Find sales where the product is a laptop and the amount is over $500, or the product is a phone with a rating ≥ 4.5:
SELECT *
FROM sales
WHERE (product = 'Laptop' AND amount > 500)
OR (product = 'Phone' AND rating >= 4.5);
String Operators
Used to manipulate text data.
| Operator | Description | Example | Result |
|---|---|---|---|
| ` | ` | Concatenation | |
~ | Regex match (case-sensitive) | 'PostgreSQL' ~ 'sql' | FALSE (no match) |
~* | Regex match (case-insensitive) | 'PostgreSQL' ~* 'sql' | TRUE (matches “SQL”) |
Example: Combine first and last names into a full name:
SELECT first_name || ' ' || last_name AS full_name
FROM customers;
Date/Time Operators
PostgreSQL has special operators for dates, times, and intervals (durations).
| Operator | Description | Example | Result |
|---|---|---|---|
+ | Add interval to date/time | '2023-10-01'::DATE + INTERVAL '7 days' | 2023-10-08 (1 week later) |
- | Subtract interval from date/time | NOW() - INTERVAL '1 month' | Current time minus 1 month |
- | Calculate difference between dates | '2023-12-31'::DATE - '2023-01-01'::DATE | 364 (days between dates) |
Example: Find sales from the last 30 days:
SELECT *
FROM sales
WHERE sale_date >= NOW() - INTERVAL '30 days';
Essential Built-In Functions
Functions extend PostgreSQL’s capabilities beyond basic operators. Let’s explore the most useful ones for beginners.
String Functions
Clean, format, or extract information from text data.
| Function | Description | Example | Result |
|---|---|---|---|
LENGTH(text) | Returns length of a string (in characters) | LENGTH('PostgreSQL') | 10 |
UPPER(text) | Converts text to uppercase | UPPER('hello') | 'HELLO' |
LOWER(text) | Converts text to lowercase | LOWER('WORLD') | 'world' |
TRIM(text) | Removes leading/trailing whitespace | TRIM(' excess space ') | 'excess space' |
SUBSTRING(text FROM start FOR length) | Extracts a substring | SUBSTRING('PostgreSQL' FROM 1 FOR 4) | 'Post' |
REPLACE(text, old, new) | Replaces all occurrences of old with new | REPLACE('hello', 'l', 'x') | 'hexxo' |
Example: Clean and standardize product names (trim spaces, uppercase):
SELECT TRIM(UPPER(product)) AS cleaned_product
FROM sales;
Numeric Functions
Perform calculations on numbers (integers, decimals, etc.).
| Function | Description | Example | Result |
|---|---|---|---|
ROUND(number, decimals) | Rounds to decimals places (default: 0) | ROUND(123.456, 2) | 123.46 |
CEIL(number) | Rounds up to the nearest integer | CEIL(4.2) | 5 |
FLOOR(number) | Rounds down to the nearest integer | FLOOR(4.9) | 4 |
ABS(number) | Returns absolute value | ABS(-7.5) | 7.5 |
Example: Round sale amounts to 2 decimal places for currency:
SELECT amount, ROUND(amount, 2) AS rounded_amount
FROM sales;
Date/Time Functions
Work with dates, times, and timestamps.
| Function | Description | Example | Result (depends on current time) |
|---|---|---|---|
NOW() | Returns current date and time (timestamp) | NOW() | 2023-10-05 14:30:00.123456 |
CURRENT_DATE | Returns current date (no time) | CURRENT_DATE | 2023-10-05 |
EXTRACT(field FROM date) | Extracts a part of a date (e.g., year, month) | EXTRACT(YEAR FROM '2023-10-05'::DATE) | 2023 |
TO_CHAR(date, format) | Formats a date/time as a string | TO_CHAR('2023-10-05'::DATE, 'FMMonth DD, YYYY') | 'October 05, 2023' |
AGE(date1, date2) | Calculates the interval between two dates | AGE(NOW(), '2023-01-'01'::DATE) | 9 mons 4 days (approx) |
Example: Format sale dates as “Month Day, Year”:
SELECT TO_CHAR(sale_date, 'FMMonth DD, YYYY') AS formatted_date
FROM sales;
Aggregate Functions
Calculate a single result from a set of rows (e.g., sum, average). Often used with GROUP BY.
| Function | Description | Example | Result |
|---|---|---|---|
COUNT(column) | Counts non-null values in a column | COUNT(customer_id) | Total number of customers (non-null) |
SUM(column) | Sums numeric values | SUM(amount) | Total sales amount |
AVG(column) | Calculates average of numeric values | AVG(amount) | Average sale amount |
MIN(column) | Returns smallest value | MIN(amount) | Smallest sale amount |
MAX(column) | Returns largest value | MAX(amount) | Largest sale amount |
Example: Calculate total, average, min, and max sales per product:
SELECT product,
COUNT(*) AS total_sales,
SUM(amount) AS total_revenue,
AVG(amount) AS avg_sale,
MIN(amount) AS min_sale,
MAX(amount) AS max_sale
FROM sales
GROUP BY product;
Array & JSON Functions
PostgreSQL natively supports arrays and JSON, with functions to manipulate them.
Array Functions
| Function | Description | Example | Result |
|---|---|---|---|
ARRAY_AGG(column) | Aggregates values into an array | ARRAY_AGG(product) | {Laptop,Phone,Tablet} (array of products) |
UNNEST(array) | Expands an array into rows | UNNEST(ARRAY['a', 'b', 'c']) | a, b, c (each in a row) |
JSON Functions
| Function | Description | Example | Result |
|---|---|---|---|
jsonb_extract_path_text(jsonb_column, 'key') | Extracts text from a JSONB field | jsonb_extract_path_text(customer_data, 'email') | '[email protected]' (if customer_data has {"email": "[email protected]"}) |
Advanced Functions
Once you’re comfortable with essentials, explore these advanced but powerful functions.
Window Functions
Window functions perform calculations across a set of table rows related to the current row (without grouping them into a single result). Common use cases: ranking, row numbering, running totals.
| Function | Description | Example |
|---|---|---|
ROW_NUMBER() OVER (ORDER BY column) | Assigns a unique row number (1, 2, 3…) ordered by column | ROW_NUMBER() OVER (ORDER BY amount DESC) (rank sales by amount) |
RANK() OVER (ORDER BY column) | Assigns rank (ties get same rank, next rank skips) | RANK() OVER (ORDER BY amount DESC) |
SUM(column) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) | Running total (sum up to current row) | SUM(amount) OVER (ORDER BY sale_date) |
Example: Rank products by total sales (descending):
SELECT product,
SUM(amount) AS total_revenue,
RANK() OVER (ORDER BY SUM(amount) DESC) AS revenue_rank
FROM sales
GROUP BY product;
Conditional Functions
Handle logic based on conditions (e.g., NULL values, custom rules).
| Function | Description | Example | Result |
|---|---|---|---|
CASE | Conditional logic (like if-else) | CASE WHEN amount > 500 THEN 'High' ELSE 'Low' END AS sale_category | 'High' or 'Low' |
COALESCE(value1, value2, ...) | Returns first non-null value | COALESCE(customer_email, '[email protected]') | Uses customer_email if not null; else 'no-email...' |
NULLIF(value1, value2) | Returns NULL if value1 = value2; else value1 | NULLIF(amount, 0) | NULL if amount is 0; else amount |
Example: Categorize sales and handle missing emails:
SELECT customer_name,
COALESCE(customer_email, '[email protected]') AS email,
CASE
WHEN amount > 1000 THEN 'Premium'
WHEN amount > 500 THEN 'Standard'
ELSE 'Basic'
END AS sale_tier
FROM sales;
Practical Examples: Putting It All Together
Let’s apply what we’ve learned with a realistic scenario. Suppose we have a sales table with:
| Column | Type | Description |
|---|---|---|
| id | INT | Unique sale ID |
| product | VARCHAR | Product sold |
| sale_date | TIMESTAMP | Date/time of sale |
| amount | NUMERIC | Sale amount (USD) |
| customer_name | VARCHAR | Customer’s name |
| customer_email | VARCHAR | Customer’s email (may be NULL) |
Example 1: Clean and Analyze Customer Data
-- Clean customer names (trim, uppercase) and handle missing emails
SELECT TRIM(UPPER(customer_name)) AS cleaned_name,
COALESCE(customer_email, '[email protected]') AS email,
COUNT(*) AS total_purchases,
SUM(amount) AS total_spent
FROM sales
GROUP BY cleaned_name, email
ORDER BY total_spent DESC
LIMIT 10; -- Top 10 customers
Example 2: Monthly Sales Report
-- Aggregate sales by month/year, format dates, calculate metrics
SELECT TO_CHAR(sale_date, 'YYYY-MM') AS sale_month,
COUNT(*) AS total_sales,
SUM(amount) AS total_revenue,
AVG(amount) AS avg_sale,
MAX(amount) AS largest_sale,
-- Categorize monthly revenue
CASE
WHEN SUM(amount) > 10000 THEN 'Excellent'
WHEN SUM(amount) > 5000 THEN 'Good'
ELSE 'Low'
END AS revenue_tier
FROM sales
GROUP BY sale_month
ORDER BY sale_month;
Example 3: Rank Products by Monthly Sales
-- Use window functions to rank products within each month
WITH monthly_sales AS (
SELECT TO_CHAR(sale_date, 'YYYY-MM') AS sale_month,
product,
SUM(amount) AS revenue
FROM sales
GROUP BY sale_month, product
)
SELECT sale_month,
product,
revenue,
RANK() OVER (PARTITION BY sale_month ORDER BY revenue DESC) AS monthly_rank
FROM monthly_sales
ORDER BY sale_month, monthly_rank;
Best Practices for Using Functions and Operators
To get the most out of PostgreSQL’s built-in tools:
- Prioritize Built-In Functions: They are optimized for performance (e.g.,
SUM()is faster than looping through rows in a custom script). - Mind Data Types: Ensure functions match the data type of your columns (e.g.,
TO_CHAR()for dates, not numbers). - Handle
NULLs Carefully: UseCOALESCE(),NULLIF(), orIS NULLto avoid unexpected results (e.g.,NULL + 5returnsNULL). - Test Edge Cases: For example,
AVG()ignoresNULLs, butCOUNT(*)includes all rows (even withNULLs). - Use
GROUP BYwith Aggregates: Always include non-aggregated columns inGROUP BYto avoid errors (e.g.,SELECT product, SUM(amount)requiresGROUP BY product).
Conclusion
PostgreSQL’s built-in functions and operators are indispensable tools for anyone working with data. From simple arithmetic to complex window functions, they streamline query writing, improve performance, and unlock powerful analysis capabilities.
As a beginner, focus on mastering the essentials first—arithmetic/comparison operators, string/numeric functions, and aggregates. Once comfortable, explore advanced topics like window functions and JSON manipulation. The key is practice: experiment with your own data, write queries, and refer to the official documentation for deeper dives.
Happy querying!