Clé primaire SQLite sur plusieurs colonnes

Réponses:

806

Selon la documentation , c'est

CREATE TABLE something (
  column1, 
  column2, 
  column3, 
  PRIMARY KEY (column1, column2)
);
Brian Campbell
la source
3
Eh bien, c'est vrai, mais selon la documentation, CREATE TABLE quelque chose (colonne1 PRIMARY KEY, colonne2 PRIMARY KEY); devrait aussi être possible, mais ce n’est pas le cas.
Yar
6
@Yar Les documents disent "S'il y a plus d'une clause PRIMARY KEY dans une seule instruction CREATE TABLE, c'est une erreur." Oui, les diagrammes de chemin de fer peuvent indiquer que cela est également valable, mais le texte ci-dessous précise que ce n'est pas le cas.
Brian Campbell
10
N'oubliez pas d'ajouter la partie PRIMARY KEY (colonne1, colonne2) à la fin comme dans cette réponse. Si vous essayez de l'ajouter après la définition de column2, vous obtiendrez une erreur de syntaxe .
vovahost
160
CREATE TABLE something (
  column1 INTEGER NOT NULL,
  column2 INTEGER NOT NULL,
  value,
  PRIMARY KEY ( column1, column2)
);
xiwok
la source
La clé primaire n'impose-t-elle pas un NOT NULL?
pratnala
23
@pratnala En SQL standard, oui. Dans SQLite, NULLest autorisé dans les clés primaires. Cette réponse souligne que si vous voulez un comportement plus standard, vous devez ajouter le NOT NULLvous - même. Ma réponse est juste la syntaxe très basique d'une clé primaire multi-colonnes.
Brian Campbell
42

Oui. Mais n'oubliez pas qu'une telle clé primaire autorise NULLplusieurs fois les valeurs dans les deux colonnes.

Créez une table comme telle:

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

Maintenant, cela fonctionne sans aucun avertissement:

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
la source
Y a-t-il une référence à la raison d'un tel comportement? Quelle serait une bonne façon de vider plusieurs lignes dans la base de données et de supprimer les doublons, même s'ils en contiennent NULL?
Pastafarianist
4
@Pastafarianist sqlite.org/lang_createtable.html - "Selon la norme SQL, PRIMARY KEY devrait toujours impliquer NOT NULL. Malheureusement, en raison d'un bogue dans certaines versions antérieures, ce n'est pas le cas dans SQLite. [...] NULL les valeurs sont considérées comme distinctes de toutes les autres valeurs, y compris les autres valeurs NULL. "
L'incroyable
Oui, dans SQL NULL, comparez toujours false. Pour cette raison, la théorie relationnelle exclut spécifiquement NULL comme valeur de tout composant clé. SQLite, cependant, est une pratique relationnelle. Il semble que les auteurs aient choisi d'autoriser de manière pragmatique les clés multiples mais pas "égales". De toute évidence, il est préférable de ne pas autoriser les valeurs NULL comme valeurs clés.
holdenweb
32

Basique:

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

Si vos colonnes sont des clés étrangères d'autres tables (cas courant):

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
la source
14

Les champs de clé primaire doivent être déclarés non nuls (ce n'est pas standard car la définition d'une clé primaire est qu'elle doit être unique et non nulle). Mais ci-dessous est une bonne pratique pour toutes les clés primaires multi-colonnes dans n'importe quel SGBD.

create table foo
(
  fooint integer not null
  ,foobar string not null
  ,fooval real
  ,primary key (fooint, foobar)
)
;
Ken Reed
la source
11

Depuis la version 3.8.2 de SQLite, une alternative aux spécifications explicites NOT NULL est la spécification "WITHOUT ROWID": [ 1 ]

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

Les tables "SANS ROWID" ont des avantages potentiels en termes d'efficacité, donc une alternative moins verbeuse à considérer est:

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

Par exemple, à l'invite sqlite3: sqlite> insert into t values(1,null,3); Error: NOT NULL constraint failed: t.c2

de pointe
la source
Pour quiconque lit ceci de nos jours: WITHOUT ROWIDa des implications supplémentaires, et il ne devrait pas être utilisé comme alternative à l'écriture à NOT NULLcôté de votre clé primaire.
shadowtalker
2

D'une autre manière, vous pouvez également créer la clé primaire à deux colonnes unique et la clé d' incrémentation automatiqueprimary . Tout comme ceci: https://stackoverflow.com/a/6157337

ElonChan
la source
C'est exactement ce que je cherchais. Je vous remercie!
Swadhikar C
2

PRIMARY KEY (id, name)n'a pas fonctionné pour moi. L'ajout d'une contrainte a fait le travail à la place.

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

Choxmi
la source
1

Le code suivant crée une table avec 2 colonnes comme clé primaire dans SQLite.

SOLUTION:

CREATE TABLE IF NOT EXISTS users (id TEXT NOT NULL, name TEXT NOT NULL, pet_name TEXT, PRIMARY KEY (id, name))
Naveen Kumar V
la source