@@IDENTITY после того, как оператор INSERT всегда возвращает 0
Мне нужна функция, которая выполняет инструкцию INSERT в базе данных и возвращает первичный ключ Auto_Increment. У меня есть следующий код С#, но, хотя оператор 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
Ответы
Ответ 1
1) объединить инструкцию INSERT и SELECT (concatenate using ";" ) в команду 1 db
2) используйте SCOPE_IDENTITY() вместо @@IDENTITY
INSERT INTO blabla...; SELECT OID FROM table WHERE OID = SCOPE_IDENTITY()
- обновить:
как выяснилось, вопрос был связан с MS ACCESS, я нашел эту статью, которая предполагает, что просто повторное использование первой команды и установка ее CommandText - "SELECT @@IDENTITY" должно быть достаточно.
Ответ 2
Поставщик Microsoft.Jet.OLEDB.4.0 поддерживает двигатели базы данных Jet v3 и Jet v4, однако
SELECT @@IDENTITY не поддерживается для Jet v3.
MSAccess 97 - это Jet v3 и не поддерживает SELECT @@IDENTITY; Он поддерживается на MSAccess 2000 и выше.
Ответ 3
вам нужно вернуть идентификатор одновременно с открытием начального соединения.
Верните результирующий набор из вашей вставки или выходной переменной.
Вы также должны всегда использовать идентификатор SCOPE_IDENTITY() not @@. Ссылка здесь
Вы должны добавить
SELECT SCOPE_IDENTITY()
После вставки.
Ответ 4
Вы используете Jet (не SQL Server), а Jet может обрабатывать только один оператор SQL для каждой команды, поэтому вам нужно выполнить SELECT @@IDENTITY
в отдельной команде, очевидно, что он использует то же соединение, что и INSERT
.
Ответ 5
Я думаю, вам нужно иметь идентификатор Select @@с первой командой create - попробуйте добавить его через "; SELECT @@Identity" и .ExecuteScalar инструкцию insert
Ответ 6
Есть ли триггеры на вашей таблице, которые могут вставляться в другие таблицы? Как правило, нам не рекомендуется использовать @@Identity в пользу IDENT_CURRENT, чтобы вы могли гарантировать, что вернувшаяся идентификация предназначена для только что вставленной таблицы в.
Ответ 7
Я думаю, что идентификация @@действительна только в области действия команды - в вашем случае, когда вы выполняете "инструкцию".
Измените свой "оператор" так, чтобы сама хранимая процедура вернула значение @@IDENTITY сразу после оператора INSERT и прочитала его как код возврата выполнения хранимой процедуры.
Ответ 8
Проверьте настройки своей базы данных. Некоторое время назад у меня была аналогичная проблема, и я обнаружил, что параметр подключения к серверу SQL Server не включен.
В SQL Server Management Studio вы можете найти это, щелкнув правой кнопкой мыши на сервере в обозревателе объектов, выберите "Свойства", а затем перейдите на страницу "Соединения". Посмотрите настройки "Параметры подключения по умолчанию"
Ответ 9
Разве большинство респондентов не забывают, что ассер не использует SQL Server?
По-видимому, MS Access 2000 и более поздние не поддерживает @@IDENTITY. Альтернативой является" Использование событие RowUpdated, вы можете определить, произошел ли INSERT, получить последнее значение @@IDENTITY и поместить его в столбец идентификатора локальной таблицы в DataSet.
И да, это для встроенного VBA в Access DB. Это все еще можно вызывать вне доступа через библиотеку объектов доступа.
Редактировать: хорошо, это поддерживается, извините за быстрый вызов раннего утра. Но остальная часть этого ответа может помочь.
Ответ 10
Если вы хотите получить значение автоматического запуска числа транзакций, которое вы вставляете, и вашей среды, следующей за 1. База данных - MsAccess. 2. Драйвер Jet4 со строкой подключения, подобной этой "Provider = Microsoft.Jet.OLEDB.4.0; Password = {0}; Источник данных = {1}; Persist Security Info = 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();
}
Ответ 11
Краткий ответ:
1. Создайте две команды, каждая из которых принимает один запрос.
2. Первый запрос sql - это запись INSERT.
3. Второй запрос sql: "SELECT @@Identity"; который возвращает AutoNumber.
4. Используйте cmd.ExecuteScalar(), который возвращает первый столбец первой строки.
5. Возвращенным результатом является значение AutoNumber, сгенерированное в текущем запросе вставки.
Ссылка на эту ссылку. Пример кода указан ниже. Обратите внимание на разницу в "SAME Connection VS NEW Connection". SAME Connection дает желаемый результат.
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
Ответ 12
Когда вы используете Access, посмотрите эту статью из aspfaq, прокрутите вниз примерно до половины пути вниз по странице. Код в классическом ASP, но, надеюсь, принципы должны по-прежнему стоять.
Идентификатор SELECT @@Identity в конечном итоге рассматривается как отдельный сценарий выполнения, я считаю. Код, который должен работать, будет следующим:
public int ExecuteInsertStatement(string statement)
{
InitializeAndOpenConnection();
IDbCommand cmdInsert = connection.CreateCommand();
cmdInsert.CommandText = statement + "; SELECT @@Identity";
object result = cmdInsert.ExecuteScalar();
if (object == DBNull.Value)
{
return -1;
}
else
{
return Convert.ToInt32(result);
}
}
Вероятно, вам понадобится/нужно убрать конкатенацию, которая добавит 'SELECT @@Identity' в конец кода.
Ответ 13
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