PostgreSQL Notes for Interns
Installation
Windows: Download the installer from the official PostgreSQL website and follow the setup
wizard. During installation, note the password and port (default: 5432) [1] .
Linux: Use your package manager, e.g., on Ubuntu:
sudo apt update
sudo apt install postgresql postgresql-contrib
macOS: Use the installer from the PostgreSQL site or Homebrew:
brew install postgresql
pgAdmin: A graphical tool installed with PostgreSQL for database management [2] [1] .
Types of SQL Commands
DDL (Data Definition Language): CREATE, ALTER, DROP (structure changes)
DML (Data Manipulation Language): INSERT, UPDATE, DELETE (data changes)
DQL (Data Query Language): SELECT (data retrieval)
DCL (Data Control Language): GRANT, REVOKE (permissions)
TCL (Transaction Control Language): COMMIT, ROLLBACK, SAVEPOINT
Create Database and Table
Create Database:
CREATE DATABASE mydb;
Create Table:
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
age INT,
salary NUMERIC(10,2)
);
Insert Data in the Table
INSERT INTO employees (name, age, salary)
VALUES ('John Doe', 30, 50000.00);
Insert multiple rows:
INSERT INTO employees (name, age, salary)
VALUES
('Alice', 28, 60000.00),
('Bob', 35, 70000.00);
Delete Rows and Columns
Delete Rows:
DELETE FROM employees WHERE id = 1;
Delete (Drop) Column:
ALTER TABLE employees DROP COLUMN salary;
Data Types and Constraints
Common Data Types:
INTEGER, SERIAL, VARCHAR(n), TEXT, DATE, TIMESTAMP, BOOLEAN, NUMERIC(p,s) [3] [4] .
Constraints:
PRIMARY KEY, UNIQUE, NOT NULL, CHECK, FOREIGN KEY
Example:
CREATE TABLE users (
user_id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
age INT CHECK (age >= 18)
);
Update Data
UPDATE employees SET salary = 55000 WHERE name = 'John Doe';
Update Data Using SQL Toolbar (pgAdmin)
Open pgAdmin, select the table, right-click → "View/Edit Data" → "All Rows".
Edit the data directly in the grid and click "Save".
Query Toolbar
In pgAdmin, use the "Query Tool" to write and execute SQL queries.
Altering Columns and Data Types
Add Column:
ALTER TABLE employees ADD COLUMN department VARCHAR(50);
Modify Data Type:
ALTER TABLE employees ALTER COLUMN age TYPE SMALLINT;
Importing CSV File
Through Command Line:
\copy employees(name, age, salary) FROM '/path/to/file.csv' DELIMITER ',' CSV HEADER;
Directly in pgAdmin:
Right-click the table → "Import/Export Data" → select CSV file and options.
Types of Operators in PostgreSQL
Type Examples
Arithmetic +, -, *, /, %
Comparison =, !=, <>, <, >, <=, >=
Logical AND, OR, NOT
Other IS NULL, IS NOT NULL, EXISTS
Set UNION, INTERSECT, EXCEPT
Comparison Operators
=, != or <>, <, >, <=, >=
Logical Operators
AND, OR, NOT
BETWEEN, LIKE, IN Operators
BETWEEN:
SELECT * FROM employees WHERE age BETWEEN 25 AND 35;
LIKE:
SELECT * FROM employees WHERE name LIKE 'A%';
IN:
SELECT * FROM employees WHERE department IN ('HR', 'IT');
Other Operators
IS NULL, IS NOT NULL
EXISTS
ANY, ALL
Set Operators
UNION, UNION ALL, INTERSECT, EXCEPT
Functions in SQL
Aggregate: COUNT(), SUM(), AVG(), MIN(), MAX()
String: UPPER(), LOWER(), LENGTH(), SUBSTRING()
Date/Time: NOW(), CURRENT_DATE, AGE()
Conditional: CASE, COALESCE()
Window: ROW_NUMBER(), RANK(), DENSE_RANK(), OVER()
String Functions
UPPER('abc') → 'ABC'
LOWER('ABC') → 'abc'
LENGTH('hello') → 5
SUBSTRING('abcdef', 2, 3) → 'bcd'
Date and Time Functions
NOW() → current timestamp
CURRENT_DATE → current date
AGE('2000-01-01') → interval from date
Conditional Functions
CASE:
SELECT name,
CASE
WHEN salary > 60000 THEN 'High'
ELSE 'Low'
END AS salary_level
FROM employees;
COALESCE:
SELECT COALESCE(middle_name, 'N/A') FROM employees;
Window Functions
Used for calculations across a set of table rows related to the current row.
Examples: ROW_NUMBER(), RANK(), SUM() OVER (PARTITION BY department)
Joins
Join Type Description
INNER JOIN Rows with matching values in both tables
LEFT JOIN All rows from left table, matched rows from right table
RIGHT JOIN All rows from right table, matched rows from left table
FULL JOIN All rows from both tables
Example:
SELECT a.name, b.department_name
FROM employees a
INNER JOIN departments b ON a.department_id = b.id;
CTE (Common Table Expressions)
Temporary result set for complex queries.
WITH dept_count AS (
SELECT department, COUNT(*) AS num
FROM employees
GROUP BY department
)
SELECT * FROM dept_count WHERE num > 5;
Subquery
Query inside another query.
SELECT name FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
Stored Procedures and Functions
Function Example:
CREATE FUNCTION get_employee_count() RETURNS INT AS $$
BEGIN
RETURN (SELECT COUNT(*) FROM employees);
END;
$$ LANGUAGE plpgsql;
Stored Procedure Example:
CREATE PROCEDURE raise_salary(emp_id INT, amount NUMERIC)
LANGUAGE plpgsql
AS $$
BEGIN
UPDATE employees SET salary = salary + amount WHERE id = emp_id;
END;
$$;
Tip: Practice each command in pgAdmin or psql for hands-on learning [5] [2] [1] .
⁂
PostgreSQL Functions: Syntax, Explanation, and Examples
Below you'll find explanations, syntax, and practical examples for each major PostgreSQL
function category discussed previously.
1. Aggregate Functions
Aggregate functions perform calculations on sets of rows and return a single value.
Function Description Syntax Example
Returns average SELECT AVG(column) FROM SELECT AVG(salary) FROM
AVG()
value table; employee;
SELECT COUNT(column) FROM SELECT COUNT(*) FROM
COUNT() Counts rows
table; employee;
Finds minimum SELECT MIN(column) FROM SELECT MIN(age) FROM
MIN()
value table; employee;
Finds maximum SELECT MAX(column) FROM SELECT MAX(salary) FROM
MAX()
value table; employee;
Calculates total SELECT SUM(column) FROM SELECT SUM(salary) FROM
SUM()
sum table; employee;
Group By Example:
SELECT department, AVG(salary)
FROM employee
GROUP BY department;
This calculates the average salary per department [6] [7] .
2. String Functions
String functions manipulate and analyze text data.
Function Description Syntax Example
Converts to SELECT LOWER('HELLO'); →
LOWER() LOWER(string)
lowercase hello
Converts to SELECT UPPER('hello'); →
UPPER() UPPER(string)
uppercase HELLO
Returns string
LENGTH() LENGTH(string) SELECT LENGTH('hello'); → 5
length
Concatenates CONCAT(str1, str2, SELECT CONCAT('Hello',
CONCAT()
strings ...) 'World'); → HelloWorld
Function Description Syntax Example
Extracts SUBSTRING(str FROM SELECT SUBSTRING('abcdef'
SUBSTRING()
substring start FOR count) FROM 2 FOR 3); → bcd
SELECT TRIM(' hello '); →
TRIM() Removes spaces TRIM(string)
hello
Example:
SELECT LOWER(CONCAT('Hello', 'World')); -- Output: helloworld
SELECT LENGTH('PostgreSQL'); -- Output: 10
3. Date and Time Functions
These functions handle date and time values.
Function Description Syntax Example
CURRENT_DATE Current date CURRENT_DATE SELECT CURRENT_DATE;
NOW() Current timestamp NOW() SELECT NOW();
Difference AGE(timestamp1, SELECT AGE('2025-04-25',
AGE()
between dates timestamp2) '2000-01-01');
Extracts part of EXTRACT(field FROM SELECT EXTRACT(YEAR FROM
EXTRACT()
date/time source) CURRENT_DATE);
AGE Example:
SELECT AGE('2025-04-25', '2000-01-01'); -- Returns interval (years, months, days)
4. Conditional Functions
Conditional functions return values based on specific conditions.
CASE Expression
SELECT name,
CASE
WHEN salary > 60000 THEN 'High'
ELSE 'Low'
END AS salary_level
FROM employee;
Returns 'High' if salary > 60000, else 'Low' [8] .
COALESCE()
Returns the first non-null value from a list.
SELECT COALESCE(middle_name, 'N/A') FROM employee;
If middle_name is NULL, returns 'N/A' [9] .
5. Window Functions
Window functions perform calculations across sets of rows related to the current row.
Function Description Syntax Example
SELECT name, ROW_NUMBER() OVER
Assigns unique ROW_NUMBER() OVER
ROW_NUMBER() (ORDER BY salary DESC) FROM
row number (ORDER BY column)
employee;
SELECT name, RANK() OVER
Assigns rank, RANK() OVER (ORDER
RANK() (ORDER BY salary DESC) FROM
gaps for ties BY column)
employee;
SELECT name, DENSE_RANK() OVER
Like RANK, no DENSE_RANK() OVER
DENSE_RANK() (ORDER BY salary DESC) FROM
gaps (ORDER BY column)
employee;
SUM(column) OVER SELECT id, SUM(amount) OVER
SUM() OVER Running total
(ORDER BY column) (ORDER BY id) FROM sales;
Example:
SELECT name, salary,
RANK() OVER (ORDER BY salary DESC) AS salary_rank
FROM employee;
6. Additional Useful Functions
NULLIF(expr1, expr2): Returns NULL if expr1 = expr2, else returns expr1.
GREATEST(val1, val2, ...): Returns the largest value.
LEAST(val1, val2, ...): Returns the smallest value.
Example:
SELECT NULLIF(10, 10); -- Returns NULL
SELECT GREATEST(1, 5, 3); -- Returns 5
SELECT LEAST(1, 5, 3); -- Returns 1
Summary Table
Category Example Function Syntax Example Description
Aggregate AVG() SELECT AVG(salary) FROM employee; Average value
String LOWER() SELECT LOWER('HELLO'); Lowercase text
Date/Time NOW() SELECT NOW(); Current timestamp
Conditional CASE See above Conditional logic
Window RANK() OVER See above Ranking rows
Tip: Practice these functions with your own tables to gain confidence and understanding.
⁂
PostgreSQL Equivalents and Examples for Common SQL Functions
Below are PostgreSQL equivalents, syntax, and examples for the functions you requested:
DATEADD, DATEPART, DATEDIFF, FORMAT, EOMONTH, LEAD, LAG, and PARTITION BY.
1. DATEADD
Purpose: Adds an interval to a date.
PostgreSQL Syntax:
SELECT date_column + INTERVAL '1 day' FROM table;
SELECT date_column + INTERVAL '2 month' FROM table;
Example:
SELECT CURRENT_DATE + INTERVAL '7 days' AS next_week;
2. DATEPART
Purpose: Extracts part of a date (year, month, day, etc.).
PostgreSQL Syntax:
SELECT EXTRACT(part FROM date_column) FROM table;
Example:
SELECT EXTRACT(YEAR FROM CURRENT_DATE) AS year;
SELECT EXTRACT(MONTH FROM '2025-04-25'::date) AS month;
3. DATEDIFF
Purpose: Calculates the difference between two dates.
PostgreSQL Syntax:
SELECT date1 - date2 AS difference; -- returns interval
SELECT EXTRACT(DAY FROM (date1 - date2)) AS days_diff;
Example:
SELECT '2025-04-25'::date - '2025-01-01'::date AS days_between; -- returns 114
4. FORMAT
Purpose: Formats values as strings.
PostgreSQL Syntax:
SELECT TO_CHAR(date_column, 'YYYY-MM-DD') FROM table;
SELECT TO_CHAR(numeric_column, 'FM999,999.00') FROM table;
Example:
SELECT TO_CHAR(NOW(), 'DD Mon YYYY') AS formatted_date;
SELECT TO_CHAR(12345.678, 'FM999,999.00') AS formatted_number;
5. EOMONTH (End of Month)
Purpose: Returns the last day of the month for a given date.
PostgreSQL Equivalent: Use date_trunc and interval arithmetic.
Syntax:
SELECT (date_trunc('month', date_column) + INTERVAL '1 month - 1 day')::date FROM table;
Example:
SELECT (date_trunc('month', '2025-04-25'::date) + INTERVAL '1 month - 1 day')::date AS en
-- Result: 2025-04-30
This is the standard workaround since PostgreSQL does not have a direct EOMONTH()
function [10] [11] [12] .
6. LEAD and LAG
Purpose: Accesses data from subsequent or previous rows in a result set.
Syntax:
SELECT value, LEAD(value) OVER (ORDER BY id) AS next_value FROM table;
SELECT value, LAG(value) OVER (ORDER BY id) AS prev_value FROM table;
Example:
SELECT id, salary,
LEAD(salary) OVER (ORDER BY id) AS next_salary,
LAG(salary) OVER (ORDER BY id) AS prev_salary
FROM employees;
7. PARTITION BY (with Window Functions)
Purpose: Divides result set into partitions to perform calculations.
Syntax:
SELECT department, salary,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_salary_rank
FROM employees;
Example:
This ranks employees within each department by salary.
Summary Table
PostgreSQL
Function Example
Equivalent
DATEADD date + INTERVAL SELECT CURRENT_DATE + INTERVAL '1 day';
DATEPART EXTRACT() SELECT EXTRACT(MONTH FROM CURRENT_DATE);
DATEDIFF date1 - date2 SELECT '2025-04-25'::date - '2025-01-01'::date;
PostgreSQL
Function Example
Equivalent
FORMAT TO_CHAR() SELECT TO_CHAR(NOW(), 'YYYY-MM-DD');
date_trunc + SELECT (date_trunc('month', '2025-04-25'::date) +
EOMONTH
INTERVAL INTERVAL '1 month - 1 day')::date; [10] [12]
SELECT LEAD(salary) OVER (ORDER BY id) FROM
LEAD/LAG LEAD()/LAG() OVER
employees;
PARTITION OVER (PARTITION SELECT RANK() OVER (PARTITION BY department ORDER BY
BY BY ...) salary DESC) FROM employees;
Note:
PostgreSQL does not have direct equivalents for some SQL Server functions, but the above
workarounds are standard and widely used.
For more details, refer to the [official PostgreSQL date/time functions documentation] [11] .
⁂
1. https://neon.tech/postgresql/postgresql-getting-started
2. https://www.datacamp.com/tutorial/beginners-introduction-postgresql
3. https://www.geeksforgeeks.org/postgresql-tutorial/
4. https://www.tutorialspoint.com/postgresql/index.htm
5. https://www.w3schools.com/postgresql/
6. https://neon.tech/postgresql/postgresql-aggregate-functions
7. https://www.slingacademy.com/article/postgresql-aggregation-sum-avg-min-max/
8. https://www.commandprompt.com/education/postgresql-conditional-expressions-explained-with-exam
ples/
9. https://neon.tech/postgresql/postgresql-tutorial/postgresql-coalesce
10. https://stackoverflow.com/questions/47785320/eomonth-equivalent-in-postgresql
11. https://www.postgresql.org/docs/current/functions-datetime.html
12. https://www.sherloqdata.io/sql-functions/eomonth-in-sql
PostgreSQL Advanced SQL Notes
Window Functions
Window functions perform calculations across sets of rows related to the current row, without collapsing rows like
aggregate functions do. They require the OVER clause and can include PARTITION BY, ORDER BY, and a frame clause.
Syntax:
SELECT column, window_function(args) OVER (
[PARTITION BY col1, col2]
[ORDER BY col3]
[ROWS BETWEEN ...]
) AS alias
FROM table;
• PARTITION BY: Divides data into groups (windows).
• ORDER BY: Orders rows within each partition.
• Frame clause: Limits the rows within the partition for the function.
Common Window Functions (with usage):
Function Description Example Usage
ROW_NUMBER() Row number within ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary
partition DESC)
RANK() Rank with gaps within RANK() OVER (ORDER BY score DESC)
partition
DENSE_RANK() Rank without gaps DENSE_RANK() OVER (ORDER BY score DESC)
SUM() Running total SUM(sales) OVER (PARTITION BY branch ORDER BY
sale_time)
AVG() Running average AVG(salary) OVER (PARTITION BY dept)
LAG(column, n) Value n rows before LAG(sales, 1) OVER (ORDER BY date)
LEAD(column, Value n rows after LEAD(sales, 1) OVER (ORDER BY date)
n)
NTILE(n) Divides partition into n NTILE(4) OVER (ORDER BY score)
buckets
FIRST_VALUE() Value from first row in FIRST_VALUE(salary) OVER (PARTITION BY dept ORDER BY
window salary)
LAST_VALUE() Value from last row in LAST_VALUE(salary) OVER (PARTITION BY dept ORDER BY
window salary)
NTH_VALUE() Value from nth row in NTH_VALUE(salary, 2) OVER (ORDER BY salary)
window
PERCENT_RANK() Percentage rank PERCENT_RANK() OVER (ORDER BY score)
CUME_DIST() Cumulative distribution CUME_DIST() OVER (ORDER BY score) [1][2][3]
Example Usage:
-- Running total of sales per branch ordered by sale_time
SELECT sale_time, branch,
SUM(total) OVER (PARTITION BY branch ORDER BY sale_time) AS running_total
FROM sales_data;
-- Row number within each department ordered by salary
SELECT emp_id, depname, salary,
ROW_NUMBER() OVER (PARTITION BY depname ORDER BY salary DESC) AS rn
FROM empsalary;
Types of Window Functions
• Aggregate Window Functions: SUM(), AVG(), COUNT(), MIN(), MAX()
• Ranking Functions: ROW_NUMBER(), RANK(), DENSE_RANK(), NTILE()
• Value Functions: LAG(), LEAD(), FIRST_VALUE(), LAST_VALUE(), NTH_VALUE()
• Distribution Functions: CUME_DIST(), PERCENT_RANK()[1][3][2]
Subqueries
A subquery is a query nested inside another SQL query.
Types of Subqueries in PostgreSQL
PostgreSQL supports several types of subqueries, each with its own syntax, example, and usage scenario:
1. Scalar Subquery
• Definition: Returns a single value (one row, one column).
• Syntax:
SELECT column1
FROM table1
WHERE column2 = (SELECT column3 FROM table2 WHERE condition);
• Example:
SELECT first_name, last_name, salary
FROM employees
WHERE salary > (SELECT max(salary) FROM employees WHERE first_name = 'Alexander');
• Usage: Used when you need to compare a value in the outer query to a single value returned by the subquery
(e.g., maximum, minimum, or specific value lookup)[1][2].
2. Multi-row Subquery
• Definition: Returns multiple rows (one column, multiple rows).
• Syntax:
SELECT column1
FROM table1
WHERE column2 IN (SELECT column3 FROM table2 WHERE condition);
• Example:
SELECT * FROM COMPANY WHERE ID IN (SELECT ID FROM COMPANY WHERE SALARY > 45000);
• Usage: Used with operators like IN, ANY, SOME, or ALL to compare a value to a set of values returned by the
subquery[1][3][4].
3. Row Subquery
• Definition: Returns a single row with multiple columns.
• Syntax:
SELECT column1
FROM table1
WHERE (column2, column3) = (SELECT column4, column5 FROM table2 WHERE condition);
• Example:
SELECT first_name
FROM employees
WHERE ROW(department_id, manager_id) = (
SELECT department_id, manager_id
FROM departments
WHERE location_id = 1800
);
• Usage: Used when you need to compare multiple columns at once between tables[2].
4. Correlated Subquery
• Definition: References columns from the outer query; executed once for each row processed by the outer query.
• Syntax:
SELECT column1
FROM table1 t1
WHERE column2 = (
SELECT MAX(column3)
FROM table2 t2
WHERE t2.column4 = t1.column4
);
• Example:
SELECT name
FROM employees e1
WHERE salary = (
SELECT MAX(salary)
FROM employees e2
WHERE e2.department_id = e1.department_id
);
• Usage: Useful for queries where the subquery’s result depends on the current row of the outer query[1].
5. Subquery in the FROM Clause (Derived Table)
• Definition: The subquery acts as a temporary table used by the outer query.
• Syntax:
SELECT alias.*
FROM (SELECT column1, column2 FROM table1 WHERE condition) AS alias
WHERE alias.column1 > value;
• Example:
SELECT sc1, sc2, sc3
FROM (SELECT c1 AS sc1, c2 AS sc2, c3*3 AS sc3 FROM tb1) AS sb
WHERE sc1 > 1;
• Usage: Useful for performing calculations or filtering on intermediate results[2].
General Subquery Guidelines
• Subqueries must be enclosed in parentheses.
• Scalar subqueries must return only one row and one column; otherwise, an error occurs.
• Multi-row subqueries should be used with operators that accept multiple values (IN, ANY, etc.).
• Subqueries can be used in SELECT, INSERT, UPDATE, and DELETE statements[4].
• Subqueries cannot use ORDER BY unless combined with LIMIT/OFFSET or used in the outer query[4].
Summary Table
Type Returns Common Usage Example Typical
Operator
Scalar 1 row, 1 column WHERE column = (SELECT MAX(column) FROM ...) =, <, >, <=, >=
Multi-row Multiple rows, 1 WHERE column IN (SELECT column FROM ...) IN, ANY,
column SOME, ALL
Row 1 row, multiple WHERE (col1, col2) = (SELECT col3, col4 FROM ...) =
columns
Correlated Varies WHERE column = (SELECT MAX(column) FROM ... =, <, >, etc.
WHERE ... = outer_table.column)
FROM Clause Table-like SELECT * FROM (SELECT ... FROM ...) AS alias WHERE N/A
(Derived) ...
These subquery types allow you to write flexible and powerful SQL statements in PostgreSQL[1][3][2][4].
Types of Subqueries by clause:
• WHERE Subquery: Used in the WHERE clause.
SELECT name FROM employees WHERE department_id = (SELECT id FROM departments WHERE name = 'HR');
• IN Subquery: Checks if a value matches any value in a list.
SELECT name FROM employees WHERE department_id IN (SELECT id FROM departments WHERE location =
'NY');
• EXISTS Subquery: Returns true if the subquery returns any rows.
SELECT name FROM employees WHERE EXISTS (SELECT 1 FROM salaries WHERE employees.id =
salaries.emp_id AND amount > 100000);
Common Table Expressions (CTE)
A CTE provides a temporary result set that can be referenced within a SELECT, INSERT, UPDATE, or DELETE statement.
Syntax:
WITH cte_name AS (
SELECT ...
)
SELECT * FROM cte_name;
• Simplifies complex joins or subqueries.
• Can be referenced multiple times in the main query.
Example:
WITH high_earners AS (
SELECT id, salary FROM employees WHERE salary > 100000
)
SELECT * FROM high_earners;
Recursive CTE
A recursive CTE references itself, useful for hierarchical or tree-structured data.
Syntax:
WITH RECURSIVE cte_name AS (
SELECT ... -- anchor member / base query
UNION ALL
SELECT ... FROM cte_name WHERE ... -- recursive member / recursive query
)
SELECT * FROM cte_name;
Example: Factorial Calculation
WITH RECURSIVE factorial_cte(n, factorial) AS (
SELECT 1, 1
UNION ALL
SELECT n + 1, (n + 1) * factorial FROM factorial_cte WHERE n < 5
)
SELECT * FROM factorial_cte;
Example: Hierarchical Data
WITH RECURSIVE org_chart AS (
SELECT id, name, manager_id FROM employees WHERE manager_id IS NULL
UNION ALL
SELECT e.id, e.name, e.manager_id FROM employees e
JOIN org_chart o ON e.manager_id = o.id
)
SELECT * FROM org_chart;
HAVING Clause
The HAVING clause is used to filter groups after aggregation, unlike WHERE which filters rows before aggregation.
Syntax:
SELECT department, COUNT(*) FROM employees
GROUP BY department
HAVING COUNT(*) > 5;
• Use HAVING with aggregate functions (e.g., SUM(), COUNT()).
PostgreSQL Procedures
Procedures are routines that can perform operations such as inserts, updates, and control transactions. They can accept
parameters, have output variables, and be called with or without arguments.
Basic Procedure Syntax:
CREATE PROCEDURE procedure_name([parameters])
LANGUAGE plpgsql
AS $$
BEGIN
-- statements
END;
$$;
Procedure with Parameters:
CREATE PROCEDURE raise_salary(emp_id INT, increment NUMERIC)
LANGUAGE plpgsql
AS $$
BEGIN
UPDATE employees SET salary = salary + increment WHERE id = emp_id;
END;
$$;
Procedure with Output Variable:
CREATE PROCEDURE get_salary(emp_id INT, OUT emp_salary NUMERIC)
LANGUAGE plpgsql
AS $$
BEGIN
SELECT salary INTO emp_salary FROM employees WHERE id = emp_id;
END;
$$;
Calling a Procedure with Output Variable:
CALL get_salary(101, emp_salary);
-- emp_salary will hold the output value
Modifying (ALTER) a Procedure:
ALTER PROCEDURE procedure_name(args) RENAME TO new_procedure_name;
Encryption:
• PostgreSQL does not natively support procedure encryption. You can restrict access using roles and permissions.
Stored Procedures vs. Functions
Feature Procedure Function
Returns value No (can use OUT parameters) Yes (must return a value)
Call syntax CALL procedure_name(...) SELECT function_name(...)
Transaction Can manage transactions (BEGIN/COMMIT) Cannot manage transactions
Use in queries No Yes
Stored Procedure Example in Detail
-- Create a procedure to transfer funds between accounts
CREATE PROCEDURE transfer_funds(
from_account INT,
to_account INT,
amount NUMERIC
)
LANGUAGE plpgsql
AS $$
BEGIN
UPDATE accounts SET balance = balance - amount WHERE account_id = from_account;
UPDATE accounts SET balance = balance + amount WHERE account_id = to_account;
COMMIT;
END;
$$;
-- Call the procedure
CALL transfer_funds(1001, 1002, 500);
These notes cover advanced SQL features in PostgreSQL, including window functions, subqueries, CTEs (including
recursive), the HAVING clause, and stored procedures with examples and usage details.[1][2][3][4][5]
1. https://neon.tech/postgresql/postgresql-window-function
2. https://www.postgresql.org/docs/current/functions-window.html
3. https://www.timescale.com/learn/postgresql-window-functions
4. https://www.draxlr.com/blogs/common-table-expressions-and-its-example-in-postgresql/
5. https://www.stratascratch.com/blog/learn-to-use-a-recursive-cte-in-sql-query/