Sqlite первичный ключ на нескольких столбцах


620

Каков синтаксис для указания первичного ключа в более чем 1 столбце в SQLITE?


14
Это также называется составным ключом. En.wikipedia.org/wiki/Compound_key
OneWorld

6
@OneWorld Или составной ключ, если какой-либо из столбцов не является самим ключом.
Майкл

Ответы:


806

Согласно документации это

CREATE TABLE something (
  column1, 
  column2, 
  column3, 
  PRIMARY KEY (column1, column2)
);

3
Ну, это правильно, но согласно документации, CREATE TABLE что-то (column1 PRIMARY KEY, column2 PRIMARY KEY); должно быть возможно, но это не так.
Яр

6
@ Yar Документы говорят: «Если в одном операторе CREATE TABLE более одного предложения PRIMARY KEY, это ошибка». Да, железнодорожные схемы могут указывать, что это также верно, но текст ниже поясняет, что это не так.
Брайан Кэмпбелл

10
Не забудьте добавить часть PRIMARY KEY (column1, column2) в конце, как в этом ответе. Если вы попытаетесь добавить его после определения column2, вы получите синтаксическую ошибку .
vovahost

160
CREATE TABLE something (
  column1 INTEGER NOT NULL,
  column2 INTEGER NOT NULL,
  value,
  PRIMARY KEY ( column1, column2)
);

Разве первичный ключ не устанавливает NOT NULL?
Пратнала

23
@pratnala В стандартном SQL, да. В SQLite NULLдопускается в первичных ключах. Этот ответ подчеркивает, что если вы хотите более стандартного поведения, вам нужно добавить NOT NULLсебя. Мой ответ - это самый простой синтаксис первичного ключа из нескольких столбцов.
Брайан Кэмпбелл

42

Да. Но помните, что такой первичный ключ допускает NULLзначения в обоих столбцах несколько раз.

Создайте таблицу как таковую:

    sqlite> CREATE TABLE something (
column1, column2, value, PRIMARY KEY (column1, column2));

Теперь это работает без предупреждения:

sqlite> insert into something (value) VALUES ('bla-bla');
sqlite> insert into something (value) VALUES ('bla-bla');
sqlite> select * from something;
NULL|NULL|bla-bla
NULL|NULL|bla-bla

Есть ли ссылка на причину такого поведения? Что может быть хорошим способом вывести несколько строк в базу данных и при этом удалить дубликаты, даже если они содержат NULL?
Пастафарианист

4
@Pastafarianist sqlite.org/lang_createtable.html - «Согласно стандарту SQL, PRIMARY KEY всегда должен подразумевать NOT NULL. К сожалению, из-за ошибки в некоторых ранних версиях это не так в SQLite. [...] NULL значения считаются отличными от всех других значений, включая другие NULL. "
Невероятный Ян

Да, в SQL NULL всегда сравнивают false. Из-за этого реляционная теория специально исключает NULL в качестве значения любого ключевого компонента. SQLite, однако, является реляционной практикой. Кажется, авторы решили прагматично разрешить множественные, но не «равные» ключи. Очевидно, что предпочтительнее не допускать значения NULL в качестве ключевых значений.
holdenweb

32

Базовый:

CREATE TABLE table1 (
    columnA INTEGER NOT NULL,
    columnB INTEGER NOT NULL,
    PRIMARY KEY (columnA, columnB)
);

Если ваши столбцы являются внешними ключами других таблиц (общий случай):

CREATE TABLE table1 (
    table2_id INTEGER NOT NULL,
    table3_id INTEGER NOT NULL,
    FOREIGN KEY (table2_id) REFERENCES table2(id),
    FOREIGN KEY (table3_id) REFERENCES table3(id),
    PRIMARY KEY (table2_id, table3_id)
);

CREATE TABLE table2 (
    id INTEGER NOT NULL,
    PRIMARY KEY id
);

CREATE TABLE table3 (
    id INTEGER NOT NULL,
    PRIMARY KEY id
);

14

Поля первичного ключа должны быть объявлены как не нулевые (это не стандартно, поскольку определение первичного ключа состоит в том, что он должен быть уникальным, а не нулевым). Но ниже приведена хорошая практика для всех многоколоночных первичных ключей в любой СУБД.

create table foo
(
  fooint integer not null
  ,foobar string not null
  ,fooval real
  ,primary key (fooint, foobar)
)
;

11

Начиная с версии 3.8.2 SQLite, альтернативой явным спецификациям NOT NULL является спецификация «БЕЗ ROWID»: [ 1 ]

NOT NULL is enforced on every column of the PRIMARY KEY
in a WITHOUT ROWID table.

Таблицы «БЕЗ КРУГЛЫХ» имеют потенциальные преимущества в эффективности, поэтому следует рассмотреть менее подробную альтернативу:

CREATE TABLE t (
  c1, 
  c2, 
  c3, 
  PRIMARY KEY (c1, c2)
 ) WITHOUT ROWID;

Например, в командной строке sqlite3: sqlite> insert into t values(1,null,3); Error: NOT NULL constraint failed: t.c2


Для тех, кто читает это в настоящее время: WITHOUT ROWIDимеет дополнительные последствия, и его не следует использовать в качестве альтернативы записи NOT NULLрядом с вашим первичным ключом.
Shadowtalker


2

PRIMARY KEY (id, name)не работал для меня Добавление ограничения сделало работу вместо этого.

CREATE TABLE IF NOT EXISTS customer (id INTEGER, name TEXT, user INTEGER, CONSTRAINT PK_CUSTOMER PRIMARY KEY (user, id))


1

Следующий код создает таблицу с 2 столбцами в качестве первичного ключа в SQLite.

РЕШЕНИЕ:

CREATE TABLE IF NOT EXISTS users (id TEXT NOT NULL, name TEXT NOT NULL, pet_name TEXT, PRIMARY KEY (id, name))
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.