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

620

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

Богдан Гаврил MSFT
источник
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)
);
xiwok
источник
Разве первичный ключ не устанавливает 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
jsmarkus
источник
Есть ли ссылка на причину такого поведения? Что может быть хорошим способом вывести несколько строк в базу данных и при этом удалить дубликаты, даже если они содержат 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
);
compte14031879
источник
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

Другим способом вы можете также сделать первичный ключ из двух столбцовunique и ключ автоинкрементаprimary . Просто так: https://stackoverflow.com/a/6157337

ElonChan
источник
Это то, что я искал именно. Спасибо!
Свадикар C
2

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

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

Choxmi
источник
1

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

РЕШЕНИЕ:

CREATE TABLE IF NOT EXISTS users (id TEXT NOT NULL, name TEXT NOT NULL, pet_name TEXT, PRIMARY KEY (id, name))
Навин Кумар V
источник