@@ IDENTITY после оператора INSERT всегда возвращает 0 - PullRequest
13 голосов
/ 09 октября 2008

Мне нужна функция, которая выполняет оператор INSERT для базы данных и возвращает первичный ключ Auto_Increment. У меня есть следующий код C #, но, хотя оператор INSERT работает нормально (я вижу запись в базе данных, PK генерируется правильно и строки == 1), значение id всегда равно 0. Любые идеи о том, что может происходить неправильно?

    public int ExecuteInsertStatement(string statement)
    {
        InitializeAndOpenConnection();
        int id = -1;


        IDbCommand cmdInsert = connection.CreateCommand();
        cmdInsert.CommandText = statement;
        int rows = cmdInsert.ExecuteNonQuery();

        if (rows == 1)
        {
            IDbCommand cmdId = connection.CreateCommand();
            cmdId.CommandText = "SELECT @@Identity;";
            id = (int)cmdId.ExecuteScalar();
        }

        return id;
    }
    private void InitializeAndOpenConnection()
    {
        if (connection == null)
            connection = OleDbProviderFactory.Instance.CreateConnection(connectString);

        if(connection.State != ConnectionState.Open)                 
            connection.Open();
    }

В ответ на ответы я попробовал:

public int ExecuteInsertStatement(string statement, string tableName)
    {
        InitializeAndOpenConnection();
        int id = -1;
        IDbCommand cmdInsert = connection.CreateCommand();
        cmdInsert.CommandText = statement + ";SELECT OID FROM " + tableName + " WHERE OID = SCOPE_IDENTITY();";
        id = (int)cmdInsert.ExecuteScalar();

        return id;
    }

но теперь я получаю сообщение об ошибке «Обнаружены символы после завершения оператора SQL»

Я использую базу данных MS Access с подключением OleDb, Provider = Microsoft.Jet.OLEDB.4.0

Ответы [ 13 ]

15 голосов
/ 09 октября 2008

1) объединить операторы INSERT и SELECT (объединить с помощью ";") в команду 1 дБ

2) использовать SCOPE_IDENTITY () вместо @@ IDENTITY

INSERT INTO blabla ...; ВЫБЕРИТЕ OID ИЗ таблицы WHERE OID = SCOPE_IDENTITY ()

- обновление:

Поскольку выяснилось, что вопрос был связан с MS ACCESS, я обнаружил эту статью , в которой предлагается, что простого повторного использования первой команды и установки ее CommandText на "SELECT @@ IDENTITY" должно быть достаточно.

7 голосов
/ 09 октября 2008

Поставщик Microsoft.Jet.OLEDB.4.0 поддерживает ядра базы данных Jet v3 и Jet v4, однако SELECT @@ IDENTITY не поддерживается для Jet v3.

MSAccess 97 является Jet v3 и не поддерживает SELECT @@ IDENTITY; Поддерживается на MSAccess 2000 и выше.

4 голосов
/ 09 октября 2008

Вы используете Jet (не SQL Server), и Jet может обрабатывать только одну инструкцию SQL на команду, поэтому вам нужно выполнить SELECT @@IDENTITY в отдельной команде, очевидно, гарантируя, что она использует то же соединение, что и INSERT.

4 голосов
/ 09 октября 2008

вам необходимо вернуть личность одновременно с открытием начального соединения. Вернуть набор результатов из вашей вставки или выходной переменной.

Вы также должны всегда использовать SCOPE_IDENTITY (), а не @@ identity. Ссылка здесь

Вы должны добавить

SELECT SCOPE_IDENTITY() 

После вставки.

1 голос
/ 09 октября 2008

Я думаю, что вам нужно иметь идентификатор Select @@ с первой командой create - попробуйте добавить его через "; SELECT @@ Identity" и .ExecuteScalar оператор вставки

0 голосов
/ 02 июня 2015

Краткий ответ:
1. Создайте две команды, каждая из которых принимает один запрос.
2. Первый запрос sql - это запись INSERT.
3. Второй SQL-запрос "SELECT @@ Identity;" который возвращает AutoNumber.
4. Используйте cmd.ExecuteScalar (), который возвращает первый столбец первой строки.
5. Возвращенным результатом будет значение AutoNumber, сгенерированное в текущем запросе вставки.

Ссылка на эту ссылку . Пример кода как под. Обратите внимание на разницу для «ЖЕ соединения по сравнению с новым соединением». ОДНО ЖЕ Соединение дает желаемый вывод.

 class Program
{
    static string path = @"<your path>";
    static string db = @"Test.mdb";
    static void Main(string[] args)
    {
        string cs = String.Format(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}\{1}", path, db);
        // Using the same connection for the insert and the SELECT @@IDENTITY
        using (OleDbConnection con = new OleDbConnection(cs))
        {
            con.Open();
            OleDbCommand cmd = con.CreateCommand();
            for (int i = 0; i < 3; i++)
            {
                cmd.CommandText = "INSERT INTO TestTable(OurTxt) VALUES ('" + i.ToString() + "')";
                cmd.ExecuteNonQuery();

                cmd.CommandText = "SELECT @@IDENTITY";
                Console.WriteLine("AutoNumber: {0}", (int)cmd.ExecuteScalar());
            }
            con.Close();
        }
        // Using a new connection and then SELECT @@IDENTITY
        using (OleDbConnection con = new OleDbConnection(cs))
        {
            con.Open();
            OleDbCommand cmd = con.CreateCommand();
            cmd.CommandText = "SELECT @@IDENTITY";
            Console.WriteLine("\nNew connection, AutoNumber: {0}", (int)cmd.ExecuteScalar());
            con.Close();
        }
    }
}

Это должно привести к очевидным выводам:

AutoNumber: 1 <br>
AutoNumber: 2 <br>
AutoNumber: 3 <br>

New connection, AutoNumber: 0
0 голосов
/ 10 января 2010
CREATE procedure dbo.sp_whlogin
(
 @id nvarchar(20),
 @ps nvarchar(20),
 @curdate datetime,
 @expdate datetime
)

AS
BEGIN
 DECLARE @role nvarchar(20)
 DECLARE @menu varchar(255)
 DECLARE @loginid int

 SELECT     @role = RoleID
 FROM         dbo.TblUsers
 WHERE    UserID = @id AND UserPass = @ps

 if @role is not null 
 BEGIN
  INSERT INTO TblLoginLog (UserID, LoginAt, ExpireAt, IsLogin) VALUES (@id, @curdate, @expdate, 1);
  SELECT @loginid = @@IDENTITY;
  SELECT @loginid as loginid, RoleName as role, RoleMenu as menu FROM TblUserRoles WHERE RoleName = @role
 END
 else
 BEGIN
  SELECT '' as role, '' as menu
 END
END
GO
0 голосов
/ 23 мая 2009

Если вы хотите получить значение автоматически выполняемого номера транзакции, которую вы вставляете, и вашей среды, следующей 1. База данных MsAccess. 2. Драйвер - это Jet4 со строкой подключения, подобной этой: "Provider = Microsoft.Jet.OLEDB.4.0; Пароль = {0}; Источник данных = {1}; Сохранение информации о безопасности = True" 3. используйте Oledb

Вы можете применить мой пример к своему коду

OleDbConnection connection =  String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Password={0};Data Source={1};Persist Security Info=True",dbinfo.Password,dbinfo.MsAccessDBFile);
connection.Open();
OleDbTransaction transaction = null;
try{
    connection.BeginTransaction();
    String commandInsert = "INSERT INTO TB_SAMPLE ([NAME]) VALUES ('MR. DUKE')";
    OleDbCommand cmd = new OleDbCommand(commandInsert , connection, transaction);
    cmd.ExecuteNonQuery();
    String commandIndentity = "SELECT @@IDENTITY";
    cmd = new OleDbCommandcommandIndentity, connection, transaction);
    Console.WriteLine("New Running No = {0}", (int)cmd.ExecuteScalar());
    connection.Commit();
}catch(Exception ex){
    connection.Rollback();
}finally{
    connection.Close();
}   
0 голосов
/ 09 октября 2008

Разве большинство респондентов не забывают, что спрашивающий не использует SQL Server?

По-видимому, MS Access 2000 и более поздние версии не поддерживают @@ IDENTITY . Альтернативой является «Используя событие RowUpdated, вы можете определить, произошла ли INSERT, получить последнее значение @@ IDENTITY и поместите его в столбец идентификаторов локальной таблицы в наборе данных. "

И да, это для встроенного VBA в БД Access. Это по-прежнему вызывается вне Access через библиотеку объектов доступа.

Редактировать: хорошо, поддерживается, извините за грубый утренний ответ. Но остальная часть этого ответа может помочь.

0 голосов
/ 09 октября 2008

Проверьте настройки базы данных. У меня была похожая проблема некоторое время назад, и я обнаружил, что параметр соединения с SQL Server «no count» был включен.

В SQL Server Management Studio это можно найти, щелкнув правой кнопкой мыши сервер в обозревателе объектов, выберите «Свойства» и перейдите на страницу «Подключения». Посмотрите настройки для "Параметры подключения по умолчанию"

...