web-dev-qa-db-fra.com

Insertion de lignes dans un tableau avec une seule colonne IDENTITY

J'ai un administrateur de table avec une seule colonne, adminId qui est la clé primaire. En raison des règles commerciales, il doit en être ainsi.

J'aimerais comprendre une fois pour toutes comment je peux écrire des procédures stockées qui insèrent des valeurs dans des tableaux comme celui-ci. J'utilise SQL Server et T-SQL et j'ai essayé d'utiliser SCOPE_IDENTITY () mais cela ne fonctionne pas car la table a INSERT_IDENTITY à false ou off.

J'aimerais vraiment ne pas insérer de valeur fictive juste pour pouvoir insérer une nouvelle ligne. Merci!

75
Phil

Si vous avez une colonne qui est une IDENTITÉ, faites simplement ceci

INSERT MyTable DEFAULT VALUES;  --allows no column list. The default will be the IDENTITY
SELECT SCOPE_IDENTITY();

Si vous n'avez pas d'identité, pouvez-vous la définir? C'est le meilleur moyen .. et utilisez le SQL ci-dessus.

Sinon, vous souhaitez insérer une nouvelle ligne

INSERT MyTable (admidid)
OUTPUT INSERTED.admidid --returns result to caller
SELECT ISNULL(MAX(admidid), 0) + 1 FROM MyTable

Remarques:

  • Sous des charges élevées, la solution MAX peut échouer avec des doublons
  • SCOPE_IDENTITY est après le fait, pas avant
  • SCOPE_IDENTITY ne fonctionne qu'avec une colonne IDENTITY. Idem toute idiotie en utilisant IDENT_CURRENT
  • La clause de sortie remplace SCOPE_IDENTITY pour la solution MAX
131
gbn

Vous devez ajouter l'IDENTITY_INSERT à votre instruction de sélection:

SET IDENTITY_INSERT MyTable ON

INSERT INTO MyTable
(AdminCol)

SELECT AdminColValue

 FROM Tableb

Lorsque vous avez terminé, assurez-vous de vous souvenir de

SET IDENTITY_INSERT MyTable OFF

Voici une bonne description de son fonctionnement à partir de BOL: http://msdn.Microsoft.com/en-us/library/aa259221 (SQL.80) .aspx

1
DataWriter

@Phil: Ne voulez-vous pas dire que votre table a deux (2) colonnes, la colonne PK à auto-incrémentation et une colonne AdminName? S'il ne contient qu'une seule colonne où va AdminName, AdminName est le PK et vous ne pouvez pas incrémenter automatiquement une chaîne, bien sûr. Les règles métier prévoient-elles que vous fassiez d'un nom d'utilisateur Windows complet la clé primaire? Ce serait viable et logique, car vous n'auriez alors pas besoin d'un autre index unique dans la colonne AdminName.

Mais si votre table a deux colonnes, pas une:

Dans SQLServer, l'auto-incrémentation fait partie de la définition de la table/colonne. Vous définissez la colonne comme un entier, puis vous en faites également une colonne d'identité, en spécifiant l'incrément, généralement 1, mais cela peut être 2 ou 5 ou 10 ou autre. Pour insérer une ligne, il vous suffit d'insérer la ou les autres valeurs de colonne et de ne rien faire avec la colonne PK:

insert into T
(foo)   -- column(s) list
values('bar') -- values list

Votre proc stocké qui effectue l'insertion peut faire de SCOPE_IDENTITY une valeur RETURN ou SCOPE_IDENTITY peut être renvoyé au client en tant que paramètre OUT.

P.S. SCOPE_IDENTITY () renvoie la dernière valeur d'identité auto-incrémentée générée dans la portée actuelle; il ne génère pas la prochaine valeur d'identité.

MODIFIER:

Vraisemblablement, votre table Administrateurs contient un ensemble d'administrateurs. Mais s'il n'a aucune colonne autre que la colonne de clé primaire entière, il n'y a aucun moyen d'identifier les administrateurs; la seule chose que vous pouvez faire est de les distinguer les uns des autres. Cela ne vous mène pas très loin du tout. Mais si votre table Administrateur avait l'une des structures suivantes:

ID   INTEGER PRIMARY KEY AUTOINCREMENT
windowsusername   varchar(50)  (unique index)

OR

windowsusername varchar(50) primary key

vous seriez en mesure de référencer la table de l'administrateur à partir d'autres tables, et les clés étrangères seraient SIGNIFICATIVES. Et c'est précisément ce qui manque à un tableau composé d'une seule colonne entière - le sens.

Ayant deux colonnes, vous pouvez alors avoir une procédure stockée pour cela:

insert into Administrators
(windowsusername)
values('mydomain\someusername');
return SCOPE_IDENTITY();

et votre programme client récupérerait comme valeur de retour l'identifiant auto-incrémenté qui avait été généré automatiquement et affecté à la ligne nouvellement insérée. Cette approche est la pratique habituelle et j'irais même jusqu'à dire qu'elle est considérée comme une "meilleure pratique".

P.S. Vous mentionnez que vous ne saviez pas comment "insérer une valeur" si vous "n'aviez rien à insérer". Il y a là une contradiction. Si vous n'avez rien à insérer, pourquoi insérer? Pourquoi voudriez-vous créer, disons, un nouveau dossier CLIENT si vous ne savez absolument rien du client? Pas leur nom, leur ville, leur numéro de téléphone, rien?

0
Tim