web-dev-qa-db-fra.com

Comment insérer un enregistrement et renvoyer l'ID nouvellement créé à l'aide d'un seul SqlCommand?

J'utilise un objet SqlCommand pour insérer un enregistrement dans une table avec une clé primaire générée automatiquement. Comment puis-je écrire le texte de la commande pour obtenir l'ID nouvellement créé lorsque j'utilise la méthode ExecuteScalar ()?

48
Mats
INSERT INTO YourTable(val1, val2, val3 ...) 
VALUES(@val1, @val2, @val3...);
SELECT SCOPE_IDENTITY();

N'oubliez pas les points-virgules à la fin de chaque instruction.

74
Dave Markle

Ajoutez la ligne suivante à la fin de la requête SQL ...

SELECT SCOPE_IDENTITY()

Et puis utilisez la méthode ExecuteScalar sur l'objet SqlCommand ...

var rowCount = command.ExecuteScalar()
25
Andy McCluggage
insert into Yourtable()  
values()  
SELECT SCOPE_IDENTITY()

Je viens de lancer un test et de vérifier que les points-virgules sont facultatifs à l'aide de SQL Server 2005 SP2 et .Net 3.5

16
JoshBerke

Ajoutez un paramètre de sortie à l'objet de commande, puis définissez la valeur sur le nouvel ID dans la procédure stockée.

Procédure stockée:

@ID AS INT OUTPUT

[Insert Command]

SET @ID = SCOPE_IDENTITY()

. NET:

cmd.CommandText = "stored_procedure";

SqlParameter pID = new SqlParameter("ID", DBType.Int32, 4);

pID.Direction = ParameterDirection.Output;

cmd.ExecuteScalar();

int id = Convert.ToInt32(cmd.Parameters["ID"].Value.ToString());
5
Matt

N'utilisez pas @@ IDENTITY, aussi simple que cela puisse paraître. Il peut renvoyer des valeurs incorrectes.

SELECT SCOPE_IDENTITY()

semble être le choix évident.

2
Kezzer

Immédiatement après votre insertion, utilisez

SELECT CAST(scope_identity() AS bigint) ---- incase you have a return result as int64

Cela retournera la colonne créée id/identité.

2
Samiksha

Bien que j'aime la réponse de Dave Markle , (et je vois que vous aussi, puisque vous l'avez marquée comme votre réponse), cette méthode peut échouer si vous avez des déclencheurs sur votre base de données, qui auditent les opérations CUD et votre la table d'audit a une colonne IDENTITY. Il retournerait la valeur de l'identité de la table d'audit, pas la table que vous venez d'insérer, car la table d'audit se produit réellement après.

Dans ce cas, une méthode plus générique peut être utilisée qui fonctionnera dans les deux cas, indépendamment de tout audit. C'est un peu plus verbeux, mais vous en avez pour votre argent.

exemple:

@"DECLARE @tmp AS TABLE ( id int )
                    INSERT INTO case
                    (
                        caseID,
                        partID,
                        serialNumber,
                        hardware,
                        software,
                        firmware
                    )
                    OUTPUT Inserted.ID into @tmp
                    VALUES
                    (
                        @caseID,
                        @partItemID,
                        @serialNumber,
                        @hardware,
                        @software,
                        @firmware
                    )
                Select ID from @tmp" )
1
Russ

Si votre identifiant est un Guid, j'ai trouvé que cette solution était la meilleure:

INSERT INTO YourTable (val1, val2, val3) 
OUTPUT inserted.id 
VALUES (@val1, @val2, @val3)

Merci @Scott Ivey

Démo complète:

    internal static Guid InsertNote(Note note)
    {
            Guid id;

            using (
                var connection =
                    new SqlConnection(ConfigurationManager.ConnectionStrings["dbconn"].ConnectionString))
            {
                connection.Open();
                using (
                    var command =
                        new SqlCommand(
                            "INSERT INTO Notes ([Title],[Text]) " +
                            "OUTPUT inserted.id " +
                            $"VALUES ('{title}','{text}');", connection))
                {
                    command.CommandType = CommandType.Text;
                    var reader = command.ExecuteReader();
                    reader.Read();
                    id = reader.GetGuid(reader.GetOrdinal("id"));
                }
                connection.Close();
            }

            return id;
    }

Je recommanderais d'utiliser une procédure stockée, mais c'est pour les tests unitaires de notre référentiel.

1
Zymotik

Tout droit sorti du Whirlpool :

Si vous utilisez MS SQL, vous pouvez utiliser "SELECT @@ IDENTITY as Value" après votre insertion pour obtenir le dernier ID généré

et:

@@IDENTITY et SCOPE_IDENTITY renvoie la dernière valeur d'identité générée dans une table de la session en cours. Pourtant, SCOPE_IDENTITY renvoie la valeur uniquement dans la portée actuelle; @@IDENTITY n'est pas limité à une portée spécifique.

Edit: Comme indiqué dans les commentaires, vous devez toujours utiliser SCOPE_IDENTITY, ne pas @@IDENTITY.

1
Treb