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.