Skip to content

Instantly share code, notes, and snippets.

@labe
Created October 25, 2013 00:19
Show Gist options
  • Select an option

  • Save labe/7147426 to your computer and use it in GitHub Desktop.

Select an option

Save labe/7147426 to your computer and use it in GitHub Desktop.
Adding uniqueness constraints to multiple columns in SQLite

#Creating unique keys in SQLite3

##Why create a unique key?

Say you want to ensure that certain values are never duplicated across rows in a given table-- e.g., voters can vote in many polls but they can only vote in one poll once. In the votes table, a unique key would be applied to the combination of voter_id and poll_id.

Or, say you have a sections table that represents sections of university courses. A section has a teacher, a teacher can teach many sections, but obviously a teacher cannot teach multiple sections that are held during the same day/time interval. So, you'll need a unique key on teacher_id, days_held and time_block.

##Create your SQL table

From the console:

$ touch sandbox.db
$ sqlite3 sandbox.db

In SQLite3, your table without the unique key might look like this:

CREATE TABLE sections (
id INTEGER PRIMARY KEY AUTOINCREMENT,
course_id INTEGER,
teacher_id INTEGER,
days_held VARCHAR(64),
time_block VARCHAR(64)
);

Note that there are not NOT NULL constraints defined because I'm lazy and it's irrelevant to understanding unique keys + SQL.

To add a unique key, just append the code after the last column definition, with the columns combination you want to unique-ify specified in parentheses-- e.g.:

CREATE TABLE sections (
id INTEGER PRIMARY KEY AUTOINCREMENT,
course_id INTEGER,
teacher_id INTEGER,
days_held VARCHAR(64),
time_block VARCHAR(64),
UNIQUE (teacher_id, days_held, time_block)
);

You can verify that this is working by trying to insert rows where the values in those columns are duplicated.

First:

INSERT INTO sections
(course_id, teacher_id, days_held, time_block)
VALUES
(1,1,"MWF","08:00-10:00"),
(2,2,"MWF","08:00-10:00"),
(1,1,"TTH","08:00-10:00");

This executes without errors, and SELECT * FROM sections; will return three rows of data.

Now then the duplicate attempt:

INSERT INTO sections
(course_id, teacher_id, days_held, time_block)
VALUES
(1,1,"MWF","08:00-10:00");

This throws an error: Error: columns teacher_id, days_held, time_block are not unique, and SELECT * FROM sections; will still only return three rows of data.

But

INSERT INTO sections
(course_id, teacher_id, days_held, time_block)
VALUES
(1,2,"MWF","08:00-10:00"),
(1,1,"MWF","10:00-12:00");

will execute without any errors.

##Get fancy!

###Multiple unique keys for different uniqueness combos

Maybe the university also wants to ensure that no course is offered more than once per day grouping (MWF, TTH). This would require a unique key to be applied to course_id and days_held.

DROP TABLE sections;

CREATE TABLE sections (
id INTEGER PRIMARY KEY AUTOINCREMENT,
course_id INTEGER,
teacher_id INTEGER,
days_held VARCHAR(64),
time_block VARCHAR(64),
UNIQUE (teacher_id, days_held, time_block),
UNIQUE (course_id, days_held)
);

INSERT INTO sections
(course_id, teacher_id, days_held, time_block)
VALUES
(1,1,"MWF","08:00-10:00"),
(2,2,"MWF","08:00-10:00"),
(1,1,"TTH","08:00-10:00");

and test the new unique key:

INSERT INTO sections
(course_id, teacher_id, days_held, time_block)
VALUES
(1,3,"MWF","10:00-12:00");

This should return the error: Error: columns course_id, days_held are not unique, but

INSERT INTO sections
(course_id, teacher_id, days_held, time_block)
VALUES
(2,1,"TTH","10:00-12:00");

will execute without errors.

###Why do I have to drop the table? Why can't I just alter the table and add a new unique constraint?

I have no idea. I've Googled this for pages and you SHOULD be able to execute something like

ALTER TABLE sections
ADD CONSTRAINT course_days UNIQUE(course_id, days_held);

but I keep getting back Error: near "CONSTRAINT": syntax error

So, yeah. If you figure this out, let me know.

@garrykevin-ep
Copy link
Copy Markdown

same here

@akenney
Copy link
Copy Markdown

akenney commented Nov 20, 2018

According to this website,

The ALTER TABLE command can only be used in SQLite to allow the user only to rename a table or to add a new column to an existing table. It is not possible to rename a column or remove a column, or add or remove constraints from a table.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment