Introduction to PostgreSQL arrays
PostgreSQL allows columns to store multiple values of the same type in a single array. Every data type has a companion array type: integer[], text[], boolean[], and so on. Arrays are useful for storing multi-valued attributes like phone numbers, tags, or scores without requiring a separate table.
Define a one-dimensional array column with:
column_name datatype[]
Creating a table with an array column
CREATE TABLE contacts (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
phones TEXT[]
);
Inserting array data
-- Using the ARRAY constructor
INSERT INTO contacts (name, phones)
VALUES ('John Doe', ARRAY['(408)-589-5846', '(408)-589-5555']);
-- Using curly brace literal syntax
INSERT INTO contacts (name, phones) VALUES
('Lily Bush', '{"(408)-589-5841"}'),
('William Gate', '{"(408)-589-5842","(408)-589-58423"}');
Accessing array elements
PostgreSQL arrays use 1-based indexing — the first element is at index 1:
-- Get the first phone number for each contact
SELECT name, phones[1] FROM contacts;
-- Output:
-- name | phones
-- -------------+----------------
-- John Doe | (408)-589-5846
-- Lily Bush | (408)-589-5841
-- William Gate | (408)-589-5842
-- Filter by a specific array element
SELECT name FROM contacts WHERE phones[2] = '(408)-589-58423';
Updating array data
-- Update a single element
UPDATE contacts
SET phones[2] = '(408)-589-5843'
WHERE id = 3
RETURNING *;
-- Replace the entire array
UPDATE contacts
SET phones = '{"(408)-589-5843"}'
WHERE id = 3
RETURNING *;
Searching arrays with ANY()
-- Find contacts who have a specific number anywhere in the array
SELECT name, phones
FROM contacts
WHERE '(408)-589-5555' = ANY(phones);
-- Output:
-- name | phones
-- ---------+---------------------------------
-- John Doe | {(408)-589-5846,(408)-589-5555}
Expanding arrays to rows with unnest()
SELECT name, unnest(phones)
FROM contacts;
-- Output:
-- name | unnest
-- -------------+----------------
-- John Doe | (408)-589-5846
-- John Doe | (408)-589-5555
-- Lily Bush | (408)-589-5841
-- William Gate | (408)-589-5843
Production tips
- Array subscripts are 1-based in PostgreSQL — the first element is
arr[1], notarr[0]. - For large tables that need to search inside arrays, create a GIN index:
CREATE INDEX idx_phones ON contacts USING GIN (phones);then use@>for containment searches. - Avoid deeply nesting arrays or storing very large arrays in a single column — consider a child table with a foreign key for unbounded one-to-many relationships.
- Use
unnest()withWITH ORDINALITYwhen you need the position of each element alongside the value.
Reference: PostgreSQL documentation — Arrays.