SELECT
Retrieve data from tables
Select All Columns
Retrieve all columns from a table
SELECT * FROM users;Select Specific Columns
Retrieve only the columns you need
SELECT name, email, created_atFROM users;Select Distinct Values
Remove duplicate rows from results
SELECT DISTINCT countryFROM users;Column Aliases
Rename columns in output using AS
SELECT first_name AS "First Name", last_name AS "Last Name", email AS "Email Address"FROM users;Concatenate Columns
Combine multiple columns into one
SELECT first_name || ' ' || last_name AS full_name, emailFROM users;CASE Expression
Conditional logic in SELECT
SELECT name, price, CASE WHEN price < 10 THEN 'Budget' WHEN price < 50 THEN 'Standard' ELSE 'Premium' END AS price_tierFROM products;Handle NULL Values
Return first non-null value
SELECT name, COALESCE(nickname, name) AS display_name, COALESCE(phone, 'No phone') AS phoneFROM users;NULLIF Function
Return NULL if two values are equal
SELECT name, NULLIF(status, 'inactive') AS active_statusFROM users;WHERE
Filter rows with conditions
Equal Comparison
Filter rows matching exact value
SELECT * FROM usersWHERE status = 'active';Comparison Operators
Use >, <, >=, <=, <> for comparisons
SELECT * FROM productsWHERE price >= 100 AND price <= 500;BETWEEN Range
Filter values within a range (inclusive)
SELECT * FROM ordersWHERE created_at BETWEEN '2024-01-01' AND '2024-12-31';IN List
Match any value in a list
SELECT * FROM usersWHERE country IN ('USA', 'Canada', 'UK');LIKE Pattern Matching
Match patterns with wildcards
-- % matches any sequenceSELECT * FROM users WHERE email LIKE '%@gmail.com'; -- _ matches single characterSELECT * FROM products WHERE sku LIKE 'ABC-___';ILIKE (Case Insensitive)
Pattern matching ignoring case
SELECT * FROM usersWHERE name ILIKE '%john%';NULL Checks
Check for NULL or NOT NULL
-- Find rows with NULLSELECT * FROM users WHERE phone IS NULL; -- Find rows without NULLSELECT * FROM users WHERE phone IS NOT NULL;AND / OR Logic
Combine multiple conditions
SELECT * FROM usersWHERE (status = 'active' OR status = 'pending') AND created_at > '2024-01-01';NOT Operator
Negate conditions
SELECT * FROM usersWHERE NOT (status = 'deleted' OR status = 'banned');EXISTS Subquery
Check if subquery returns rows
SELECT * FROM users uWHERE EXISTS ( SELECT 1 FROM orders o WHERE o.user_id = u.id);ANY / SOME Operator
Compare against any subquery value
-- Equal to any valueSELECT * FROM productsWHERE price = ANY(SELECT price FROM featured_products); -- Greater than any (same as > MIN)SELECT * FROM productsWHERE price > ANY(SELECT price FROM budget_products);ALL Operator
Compare against all subquery values
-- Greater than all valuesSELECT * FROM productsWHERE price > ALL(SELECT price FROM budget_products); -- Not equal to all (exclude all matches)SELECT * FROM usersWHERE id <> ALL(SELECT user_id FROM banned_users);ORDER & LIMIT
Sort and paginate results
Sort Ascending
Sort results A-Z, smallest to largest
SELECT * FROM usersORDER BY created_at ASC;Sort Descending
Sort results Z-A, largest to smallest
SELECT * FROM productsORDER BY price DESC;Multi-Column Sort
Sort by multiple columns
SELECT * FROM usersORDER BY country ASC, created_at DESC;NULL Ordering
Control where NULLs appear
SELECT * FROM usersORDER BY phone NULLS LAST; -- Or put NULLs firstSELECT * FROM usersORDER BY phone NULLS FIRST;LIMIT Results
Return only first N rows
SELECT * FROM productsORDER BY created_at DESCLIMIT 10;OFFSET for Pagination
Skip rows for pagination
-- Page 1 (rows 1-10)SELECT * FROM products ORDER BY id LIMIT 10 OFFSET 0; -- Page 2 (rows 11-20)SELECT * FROM products ORDER BY id LIMIT 10 OFFSET 10; -- Page 3 (rows 21-30)SELECT * FROM products ORDER BY id LIMIT 10 OFFSET 20;FETCH FIRST (SQL Standard)
Standard SQL alternative to LIMIT
SELECT * FROM productsORDER BY price DESCFETCH FIRST 5 ROWS ONLY;Aggregates
COUNT, SUM, AVG, MIN, MAX
COUNT All Rows
Count total number of rows
SELECT COUNT(*) AS total_usersFROM users;COUNT Distinct
Count unique values
SELECT COUNT(DISTINCT country) AS countriesFROM users;SUM Values
Calculate total of numeric column
SELECT SUM(amount) AS total_revenueFROM ordersWHERE status = 'completed';AVG Average
Calculate average of numeric column
SELECT AVG(price) AS average_priceFROM products;MIN and MAX
Find smallest and largest values
SELECT MIN(price) AS cheapest, MAX(price) AS most_expensiveFROM products;Aggregate with FILTER
Apply conditions to aggregates
SELECT COUNT(*) AS total_orders, COUNT(*) FILTER (WHERE status = 'completed') AS completed, COUNT(*) FILTER (WHERE status = 'pending') AS pendingFROM orders;GROUP BY
Group rows and aggregate
Basic Grouping
Group rows by column value
SELECT country, COUNT(*) AS user_countFROM usersGROUP BY country;Group by Multiple Columns
Create groups from column combinations
SELECT country, status, COUNT(*) AS user_countFROM usersGROUP BY country, status;HAVING Filter
Filter groups after aggregation
SELECT country, COUNT(*) AS user_countFROM usersGROUP BY countryHAVING COUNT(*) > 100;ROLLUP Subtotals
Generate subtotals and grand total
SELECT country, city, COUNT(*) AS user_countFROM usersGROUP BY ROLLUP(country, city);CUBE All Combinations
Generate all grouping combinations
SELECT country, status, COUNT(*) AS user_countFROM usersGROUP BY CUBE(country, status);JOINs
Combine data from multiple tables
INNER JOIN
Return matching rows from both tables
SELECT users.name, orders.id AS order_id, orders.totalFROM usersINNER JOIN orders ON users.id = orders.user_id;LEFT JOIN
All rows from left, matching from right
SELECT users.name, orders.id AS order_idFROM usersLEFT JOIN orders ON users.id = orders.user_id;RIGHT JOIN
Matching from left, all from right
SELECT users.name, orders.id AS order_idFROM usersRIGHT JOIN orders ON users.id = orders.user_id;FULL OUTER JOIN
All rows from both tables
SELECT users.name, orders.id AS order_idFROM usersFULL OUTER JOIN orders ON users.id = orders.user_id;CROSS JOIN
Cartesian product of all rows
SELECT colors.name AS color, sizes.name AS sizeFROM colorsCROSS JOIN sizes;Self JOIN
Join table to itself
SELECT e.name AS employee, m.name AS managerFROM employees eLEFT JOIN employees m ON e.manager_id = m.id;Multiple JOINs
Join more than two tables
SELECT users.name, orders.id AS order_id, products.name AS productFROM usersINNER JOIN orders ON users.id = orders.user_idINNER JOIN order_items ON orders.id = order_items.order_idINNER JOIN products ON order_items.product_id = products.id;JOIN with USING
Shorthand when column names match
SELECT users.name, orders.totalFROM usersINNER JOIN orders USING (user_id);NATURAL JOIN
Auto-join on matching column names
-- Joins on all columns with same nameSELECT * FROM ordersNATURAL JOIN order_items; -- Be careful: joins on ALL matching names-- Prefer explicit JOIN conditionsSubqueries
Nested queries within queries
Subquery in WHERE
Use query result as filter condition
SELECT * FROM productsWHERE price > ( SELECT AVG(price) FROM products);Subquery with IN
Match against subquery results
SELECT * FROM usersWHERE id IN ( SELECT user_id FROM orders WHERE total > 1000);Subquery in FROM
Use subquery as a derived table
SELECT country, avg_orderFROM ( SELECT u.country, AVG(o.total) AS avg_order FROM users u JOIN orders o ON u.id = o.user_id GROUP BY u.country) AS country_statsWHERE avg_order > 500;Scalar Subquery in SELECT
Return single value in column
SELECT name, price, price - (SELECT AVG(price) FROM products) AS diff_from_avgFROM products;Correlated Subquery
Subquery referencing outer query
SELECT * FROM products pWHERE price > ( SELECT AVG(price) FROM products WHERE category_id = p.category_id);LATERAL Join
Subquery can reference preceding tables
SELECT u.name, recent.order_date, recent.totalFROM users uCROSS JOIN LATERAL ( SELECT order_date, total FROM orders WHERE user_id = u.id ORDER BY order_date DESC LIMIT 3) AS recent;NOT EXISTS
Check subquery returns no rows
-- Users with no ordersSELECT * FROM users uWHERE NOT EXISTS ( SELECT 1 FROM orders o WHERE o.user_id = u.id);CTEs
Common Table Expressions (WITH)
Basic CTE
Define a named subquery
WITH active_users AS ( SELECT * FROM users WHERE status = 'active')SELECT * FROM active_usersWHERE created_at > '2024-01-01';Multiple CTEs
Chain multiple CTEs together
WITH active_users AS ( SELECT * FROM users WHERE status = 'active' ), user_orders AS ( SELECT user_id, COUNT(*) AS order_count FROM orders GROUP BY user_id )SELECT u.name, COALESCE(o.order_count, 0) AS ordersFROM active_users uLEFT JOIN user_orders o ON u.id = o.user_id;Recursive CTE
Query hierarchical or tree data
WITH RECURSIVE org_chart AS ( -- Base case: top-level (no manager) SELECT id, name, manager_id, 1 AS level FROM employees WHERE manager_id IS NULL UNION ALL -- Recursive case SELECT e.id, e.name, e.manager_id, oc.level + 1 FROM employees e INNER JOIN org_chart oc ON e.manager_id = oc.id)SELECT * FROM org_chart ORDER BY level, name;Generate Number Series
Create sequence with recursive CTE
WITH RECURSIVE numbers AS ( SELECT 1 AS n UNION ALL SELECT n + 1 FROM numbers WHERE n < 100)SELECT * FROM numbers;Window Functions
ROW_NUMBER, RANK, LAG, LEAD
ROW_NUMBER
Assign sequential numbers to rows
SELECT name, price, ROW_NUMBER() OVER (ORDER BY price DESC) AS rankFROM products;RANK vs DENSE_RANK
Handle ties differently
SELECT name, price, RANK() OVER (ORDER BY price DESC) AS rank, DENSE_RANK() OVER (ORDER BY price DESC) AS dense_rankFROM products;PARTITION BY
Window function per group
SELECT category, name, price, RANK() OVER (PARTITION BY category ORDER BY price DESC) AS category_rankFROM products;LAG and LEAD
Access previous/next row values
SELECT order_date, total, LAG(total) OVER (ORDER BY order_date) AS prev_total, LEAD(total) OVER (ORDER BY order_date) AS next_totalFROM orders;Running Total
Cumulative sum with SUM window
SELECT order_date, total, SUM(total) OVER (ORDER BY order_date) AS running_totalFROM orders;Moving Average
Average over sliding window
SELECT order_date, total, AVG(total) OVER ( ORDER BY order_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW ) AS moving_avg_7dayFROM orders;FIRST_VALUE / LAST_VALUE
Get first or last value in window
SELECT name, price, FIRST_VALUE(name) OVER (ORDER BY price DESC) AS most_expensive, LAST_VALUE(name) OVER ( ORDER BY price DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS cheapestFROM products;NTILE Buckets
Divide rows into N equal groups
SELECT name, price, NTILE(4) OVER (ORDER BY price) AS quartileFROM products;String Functions
Text manipulation functions
CONCAT / ||
Join strings together
SELECT CONCAT(first_name, ' ', last_name) AS full_name, first_name || ' ' || last_name AS full_name_altFROM users;UPPER / LOWER
Change case
SELECT UPPER(name) AS uppercase, LOWER(email) AS lowercase, INITCAP(name) AS titlecaseFROM users;SUBSTRING
Extract part of string
SELECT SUBSTRING(phone FROM 1 FOR 3) AS area_code, SUBSTRING(email FROM '@(.+)$') AS domainFROM users;TRIM / LTRIM / RTRIM
Remove whitespace or characters
SELECT TRIM(' hello ') AS trimmed, LTRIM(' hello ') AS left_trimmed, RTRIM(' hello ') AS right_trimmed, TRIM(BOTH '-' FROM '--hello--') AS custom_trimFROM users;REPLACE
Replace substring with another
SELECT REPLACE(phone, '-', '') AS phone_digits, REPLACE(name, 'Mr. ', '') AS name_no_titleFROM users;SPLIT_PART
Split string and get part
SELECT email, SPLIT_PART(email, '@', 1) AS username, SPLIT_PART(email, '@', 2) AS domainFROM users;LENGTH / CHAR_LENGTH
Get string length
SELECT name, LENGTH(name) AS name_length, CHAR_LENGTH(name) AS char_countFROM users;POSITION / STRPOS
Find substring position
SELECT email, POSITION('@' IN email) AS at_position, STRPOS(email, '@') AS at_position_altFROM users;Date & Time
Date and time functions
Current Date/Time
Get current timestamp
SELECT CURRENT_DATE AS today, CURRENT_TIME AS now_time, CURRENT_TIMESTAMP AS now_full, NOW() AS now_func;EXTRACT Parts
Get specific date/time parts
SELECT created_at, EXTRACT(YEAR FROM created_at) AS year, EXTRACT(MONTH FROM created_at) AS month, EXTRACT(DAY FROM created_at) AS day, EXTRACT(HOUR FROM created_at) AS hourFROM orders;DATE_TRUNC
Truncate to specified precision
SELECT created_at, DATE_TRUNC('month', created_at) AS month_start, DATE_TRUNC('year', created_at) AS year_start, DATE_TRUNC('hour', created_at) AS hour_startFROM orders;Date Arithmetic
Add or subtract intervals
SELECT NOW() AS now, NOW() + INTERVAL '1 day' AS tomorrow, NOW() - INTERVAL '1 week' AS last_week, NOW() + INTERVAL '3 months' AS three_monthsFROM orders;AGE Function
Calculate difference between dates
SELECT name, birth_date, AGE(birth_date) AS age, AGE(NOW(), hire_date) AS tenureFROM employees;TO_CHAR Formatting
Format date as string
SELECT created_at, TO_CHAR(created_at, 'YYYY-MM-DD') AS iso_date, TO_CHAR(created_at, 'Mon DD, YYYY') AS pretty_date, TO_CHAR(created_at, 'HH24:MI:SS') AS time_24hFROM orders;Generate Date Series
Create sequence of dates
SELECT date::dateFROM generate_series( '2024-01-01'::date, '2024-12-31'::date, '1 month'::interval) AS date;JSON
JSON data manipulation
Access JSON Fields
Use -> and ->> operators
SELECT data->'name' AS name_json, -- returns JSON data->>'name' AS name_text, -- returns text data->'address'->>'city' AS city -- nested accessFROM users;JSON Path
Use #> and #>> for path access
SELECT data #> '{address,city}' AS city_json, data #>> '{address,city}' AS city_text, data #>> '{tags,0}' AS first_tagFROM users;JSONB Containment
Check if JSON contains value
-- Contains this JSON?SELECT * FROM productsWHERE data @> '{"status": "active"}'; -- Is contained by?SELECT * FROM productsWHERE '{"status": "active", "type": "book"}' @> data;Build JSON Objects
Create JSON from columns
SELECT json_build_object( 'id', id, 'name', name, 'email', email ) AS user_jsonFROM users;JSON Aggregation
Aggregate rows into JSON array
SELECT category, json_agg(name) AS product_names, json_agg(json_build_object('name', name, 'price', price)) AS productsFROM productsGROUP BY category;JSONB_SET Update
Update nested JSON value
UPDATE usersSET data = jsonb_set( data, '{address,city}', '"New York"')WHERE id = 1;INSERT / UPDATE / DELETE
Modify data in tables
Basic INSERT
Insert a single row
INSERT INTO users (name, email, status)VALUES ('John Doe', 'john@example.com', 'active');Insert Multiple Rows
Insert several rows at once
INSERT INTO users (name, email)VALUES ('Alice', 'alice@example.com'), ('Bob', 'bob@example.com'), ('Carol', 'carol@example.com');INSERT with RETURNING
Get inserted data back
INSERT INTO users (name, email)VALUES ('John', 'john@example.com')RETURNING id, name, created_at;INSERT from SELECT
Insert rows from a query
INSERT INTO users_archive (name, email)SELECT name, emailFROM usersWHERE status = 'inactive';UPSERT (ON CONFLICT)
Insert or update if exists
INSERT INTO users (id, name, email)VALUES (1, 'John', 'john@example.com')ON CONFLICT (id) DO UPDATESET name = EXCLUDED.name, email = EXCLUDED.email;INSERT or Ignore
Skip if already exists
INSERT INTO users (email, name)VALUES ('john@example.com', 'John')ON CONFLICT (email) DO NOTHING;Basic UPDATE
Update rows matching condition
UPDATE usersSET status = 'inactive', updated_at = NOW()WHERE last_login < '2024-01-01';UPDATE with RETURNING
Get updated rows back
UPDATE productsSET price = price * 1.10WHERE category = 'electronics'RETURNING id, name, price;UPDATE with FROM
Update using another table
UPDATE ordersSET status = 'shipped'FROM shipmentsWHERE orders.id = shipments.order_id AND shipments.shipped_at IS NOT NULL;Basic DELETE
Delete rows matching condition
DELETE FROM usersWHERE status = 'deleted' AND updated_at < NOW() - INTERVAL '30 days';DELETE with RETURNING
Get deleted rows back
DELETE FROM sessionsWHERE expires_at < NOW()RETURNING id, user_id;TRUNCATE Table
Delete all rows quickly
-- Fast delete all rows (resets sequences)TRUNCATE TABLE logs; -- Truncate multiple tablesTRUNCATE TABLE orders, order_itemsRESTART IDENTITY CASCADE;Tables & DDL
CREATE, ALTER, DROP structures
CREATE TABLE
Create a new table
CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(255) UNIQUE NOT NULL, status VARCHAR(20) DEFAULT 'active', created_at TIMESTAMP DEFAULT NOW());CREATE IF NOT EXISTS
Create table only if missing
CREATE TABLE IF NOT EXISTS logs ( id SERIAL PRIMARY KEY, message TEXT, level VARCHAR(20), created_at TIMESTAMP DEFAULT NOW());CREATE TABLE AS
Create table from query
CREATE TABLE active_users ASSELECT id, name, emailFROM usersWHERE status = 'active';Add Column
Add a new column to table
ALTER TABLE usersADD COLUMN phone VARCHAR(20); -- With default valueALTER TABLE usersADD COLUMN is_verified BOOLEAN DEFAULT false;Drop Column
Remove a column from table
ALTER TABLE usersDROP COLUMN phone; -- Drop if existsALTER TABLE usersDROP COLUMN IF EXISTS temp_field;Rename Column / Table
Rename columns or tables
-- Rename columnALTER TABLE usersRENAME COLUMN name TO full_name; -- Rename tableALTER TABLE usersRENAME TO customers;Change Column Type
Modify column data type
ALTER TABLE productsALTER COLUMN price TYPE NUMERIC(10,2); -- With conversionALTER TABLE usersALTER COLUMN age TYPE INTEGERUSING age::INTEGER;Set / Drop Default
Change column default value
-- Set defaultALTER TABLE usersALTER COLUMN status SET DEFAULT 'pending'; -- Remove defaultALTER TABLE usersALTER COLUMN status DROP DEFAULT;DROP TABLE
Delete a table
DROP TABLE users; -- Drop if existsDROP TABLE IF EXISTS temp_users; -- Drop with dependent objectsDROP TABLE orders CASCADE;CREATE INDEX
Create index for faster queries
-- Basic indexCREATE INDEX idx_users_email ON users(email); -- Unique indexCREATE UNIQUE INDEX idx_users_username ON users(username); -- Multi-column indexCREATE INDEX idx_orders_user_date ON orders(user_id, created_at);DROP INDEX
Remove an index
DROP INDEX idx_users_email; DROP INDEX IF EXISTS idx_temp;CREATE VIEW
Create a virtual table
CREATE VIEW active_orders ASSELECT o.id, u.name, o.total, o.created_atFROM orders oJOIN users u ON o.user_id = u.idWHERE o.status = 'active'; -- Then query like a tableSELECT * FROM active_orders;Constraints
PRIMARY KEY, FOREIGN KEY, UNIQUE
PRIMARY KEY
Unique identifier for rows
-- Inline definitionCREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(100)); -- Named constraintCREATE TABLE products ( id INTEGER, sku VARCHAR(50), CONSTRAINT pk_products PRIMARY KEY (id));FOREIGN KEY
Reference another table
CREATE TABLE orders ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id), total DECIMAL(10,2)); -- With ON DELETE actionCREATE TABLE comments ( id SERIAL PRIMARY KEY, post_id INTEGER REFERENCES posts(id) ON DELETE CASCADE, content TEXT);UNIQUE Constraint
Prevent duplicate values
-- Single columnCREATE TABLE users ( id SERIAL PRIMARY KEY, email VARCHAR(255) UNIQUE); -- Multiple columnsCREATE TABLE memberships ( user_id INTEGER, group_id INTEGER, UNIQUE (user_id, group_id));NOT NULL
Require a value
CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(255) NOT NULL);CHECK Constraint
Validate column values
CREATE TABLE products ( id SERIAL PRIMARY KEY, name VARCHAR(100), price DECIMAL(10,2) CHECK (price > 0), quantity INTEGER CHECK (quantity >= 0)); -- Named checkCREATE TABLE users ( age INTEGER, CONSTRAINT valid_age CHECK (age >= 0 AND age < 150));DEFAULT Value
Set automatic default
CREATE TABLE posts ( id SERIAL PRIMARY KEY, title VARCHAR(200), status VARCHAR(20) DEFAULT 'draft', views INTEGER DEFAULT 0, created_at TIMESTAMP DEFAULT NOW());Add Constraint to Existing Table
Add constraints with ALTER
-- Add foreign keyALTER TABLE ordersADD CONSTRAINT fk_orders_userFOREIGN KEY (user_id) REFERENCES users(id); -- Add unique constraintALTER TABLE usersADD CONSTRAINT unique_email UNIQUE (email); -- Add check constraintALTER TABLE productsADD CONSTRAINT positive_price CHECK (price > 0);Drop Constraint
Remove a constraint
ALTER TABLE ordersDROP CONSTRAINT fk_orders_user; ALTER TABLE usersDROP CONSTRAINT IF EXISTS unique_email;Set Operations
UNION, INTERSECT, EXCEPT
UNION
Combine results, remove duplicates
SELECT name, email FROM customersUNIONSELECT name, email FROM suppliers;UNION ALL
Combine results, keep duplicates
SELECT product_id, 'sale' AS type FROM salesUNION ALLSELECT product_id, 'return' AS type FROM returns;INTERSECT
Rows in both queries
SELECT user_id FROM premium_usersINTERSECTSELECT user_id FROM active_users;EXCEPT
Rows in first but not second
SELECT user_id FROM all_usersEXCEPTSELECT user_id FROM banned_users;ORDER with Set Operations
Sort combined results
(SELECT name, 'customer' AS type FROM customers)UNION(SELECT name, 'supplier' AS type FROM suppliers)ORDER BY name;Type Casting
Convert between data types
:: Operator
PostgreSQL cast shorthand
SELECT '123'::INTEGER AS num, '2024-01-15'::DATE AS date, 123::TEXT AS str, '3.14'::NUMERIC AS decimal;CAST Function
Standard SQL casting
SELECT CAST('123' AS INTEGER) AS num, CAST('2024-01-15' AS DATE) AS date, CAST(price AS INTEGER) AS roundedFROM products;Numeric Conversions
Convert between number types
SELECT 1234.567::INTEGER AS truncated, -- 1234 1234.567::NUMERIC(10,1) AS rounded, -- 1234.6 '99.99'::DECIMAL(5,2) AS decimal;Date/Time Conversions
Convert date and time types
SELECT NOW()::DATE AS today, NOW()::TIME AS current_time, '2024-01-15 10:30:00'::TIMESTAMP AS ts, EXTRACT(EPOCH FROM NOW())::INTEGER AS unix;Boolean Conversions
Convert to/from boolean
SELECT 'true'::BOOLEAN, 'yes'::BOOLEAN, '1'::BOOLEAN, 1::BOOLEAN, true::INTEGER; -- 1JSON Conversions
Convert to/from JSON
SELECT '{"name": "John"}'::JSON, '{"name": "John"}'::JSONB, row_to_json(users.*) FROM users;Numeric Functions
ROUND, ABS, CEIL, FLOOR
ROUND
Round to decimal places
SELECT ROUND(3.14159) AS whole, -- 3 ROUND(3.14159, 2) AS two_dec, -- 3.14 ROUND(1234.5, -2) AS hundreds; -- 1200CEIL / FLOOR
Round up or down
SELECT CEIL(4.2) AS ceiling, -- 5 FLOOR(4.8) AS floor, -- 4 CEIL(-4.2) AS neg_ceil, -- -4 FLOOR(-4.8) AS neg_fl; -- -5TRUNC
Truncate toward zero
SELECT TRUNC(4.9) AS truncated, -- 4 TRUNC(-4.9) AS neg_trunc, -- -4 TRUNC(123.456, 1) AS one_dec; -- 123.4ABS
Absolute value
SELECT ABS(-5) AS positive, -- 5 ABS(5) AS still_pos, -- 5 ABS(price - 100) AS diffFROM products;POWER / SQRT
Exponents and square root
SELECT POWER(2, 3) AS eight, -- 8 POWER(10, 2) AS hundred, -- 100 SQRT(16) AS four, -- 4 SQRT(2) AS root2; -- 1.414...MOD / %
Remainder after division
SELECT MOD(10, 3) AS remainder, -- 1 17 % 5 AS mod_operator, -- 2 MOD(id, 2) AS is_oddFROM users;RANDOM
Generate random numbers
SELECT RANDOM() AS zero_to_one, FLOOR(RANDOM() * 100) AS zero_to_99, FLOOR(RANDOM() * (max - min + 1) + min) AS range; -- Random rowSELECT * FROM usersORDER BY RANDOM()LIMIT 1;SIGN / DIV
Sign and integer division
SELECT SIGN(-5) AS negative, -- -1 SIGN(0) AS zero, -- 0 SIGN(5) AS positive, -- 1 DIV(17, 5) AS int_div; -- 3Arrays
PostgreSQL array operations
Array Literals
Create array values
SELECT ARRAY[1, 2, 3] AS int_array, ARRAY['a', 'b', 'c'] AS text_array, '{1,2,3}'::INTEGER[] AS cast_array;Access Array Elements
Get elements by index (1-based)
SELECT (ARRAY['a','b','c'])[1] AS first, -- 'a' (ARRAY['a','b','c'])[2:3] AS slice, -- {'b','c'} tags[1] AS first_tagFROM posts;ANY / ALL with Arrays
Compare against array values
-- Match any value in arraySELECT * FROM usersWHERE status = ANY(ARRAY['active', 'pending']); -- Match all valuesSELECT * FROM productsWHERE price > ALL(ARRAY[10, 20, 30]);Array Contains
Check array containment
-- Contains all elementsSELECT * FROM postsWHERE tags @> ARRAY['sql', 'database']; -- Is contained bySELECT * FROM postsWHERE tags <@ ARRAY['sql', 'database', 'postgresql']; -- Overlaps (has common elements)SELECT * FROM postsWHERE tags && ARRAY['sql', 'nosql'];ARRAY_AGG
Aggregate values into array
SELECT category, ARRAY_AGG(name) AS product_names, ARRAY_AGG(DISTINCT status) AS statusesFROM productsGROUP BY category;UNNEST
Expand array to rows
SELECT UNNEST(ARRAY[1, 2, 3]) AS num; -- Expand column arraySELECT id, UNNEST(tags) AS tagFROM posts;Array Functions
Common array operations
SELECT ARRAY_LENGTH(ARRAY[1,2,3], 1) AS len, -- 3 ARRAY_CAT(ARRAY[1,2], ARRAY[3,4]) AS concat, -- {1,2,3,4} ARRAY_APPEND(ARRAY[1,2], 3) AS append, -- {1,2,3} ARRAY_REMOVE(ARRAY[1,2,3], 2) AS removed; -- {1,3}Array Search
Find elements in arrays
SELECT ARRAY_POSITION(ARRAY['a','b','c'], 'b') AS pos, -- 2 'b' = ANY(ARRAY['a','b','c']) AS exists, -- true CARDINALITY(ARRAY[1,2,3]) AS size; -- 3