What does a UNIQUE constraint guarantee, and what does it not?
A UNIQUE constraint guarantees that no two rows in the table hold the same value in the constrained column or column combination. That is the whole of it, and the simplicity is what makes it valuable: the rule is enforced by the engine on every insert and update, no matter which code path is writing.
What it does not guarantee is worth being precise about. It does not guarantee that the value identifies the row — that is the primary key's job, and a UNIQUE column is often nullable, so it may not identify anything. It does not guarantee case-insensitive uniqueness unless the column's collation says so: in SQLite and PostgreSQL, '[email protected]' and '[email protected]' are two different values under a UNIQUE constraint, so two accounts can be created that differ only in case. It does not guarantee anything across tables, and it does not stop a duplicate if the value is NULL — because SQL treats each NULL as distinct from every other NULL.
That NULL behaviour is the detail that catches people out, and it flows directly from three-valued logic. A unique constraint asks whether two values are known to be equal. Two unknowns are not known to be equal, so the uniqueness rule never fires for NULLs. The practical effect is that a table with a nullable unique email column can hold any number of rows with a NULL email, which is usually what you want — an unknown email is not a duplicate of another unknown email.
One more thing it does not do: enforce a rule across a join. If two tables each have a UNIQUE column, nothing stops the same value appearing in both. If that matters, it needs a foreign key or a shared lookup table.