INSERT语句后@@ IDENTITY始终返回0

时间:2008-10-09 09:38:52

标签: sql database ms-access primary-key jet

我需要一个在数据库上执行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语句结束后找到的字符”

我正在使用带有OleDb连接的MS Access数据库,Provider = Microsoft.Jet.OLEDB.4.0

13 个答案:

答案 0 :(得分:15)

1)将INSERT和SELECT语句(使用“;”连接)组合成1 db命令

2)使用SCOPE_IDENTITY()代替@@ IDENTITY

INSERT INTO blabla ...; SELECT OID FROM表WHERE OID = SCOPE_IDENTITY()

- 更新:

因为事实证明问题与MS ACCESS有关,我发现this article表明只需重用第一个命令并将其CommandText设置为“SELECT @@ IDENTITY”即可。

答案 1 :(得分:7)

但是,Microsoft.Jet.OLEDB.4.0提供程序支持Jet v3和Jet v4数据库引擎 Jet v3不支持SELECT @@ IDENTITY。

MSAccess 97是Jet v3,不支持SELECT @@ IDENTITY;它支持MSAccess 2000及更高版本。

答案 2 :(得分:4)

您需要在打开初始连接的同时返回身份。 从插入或输出变量返回结果集。

您还应始终使用SCOPE_IDENTITY()而非@@ identity。 Reference here

你应该添加

SELECT SCOPE_IDENTITY() 

插入后。

答案 3 :(得分:4)

您正在使用Jet(而不是SQL Server),Jet只能为每个命令处理一个SQL语句,因此您需要在单独的命令中执行SELECT @@IDENTITY,显然确保它使用与{{1}相同的连接}}

答案 4 :(得分:1)

我认为您需要使用第一个create命令选择Select @@ identity - 尝试通过“; SELECT @@ Identity”和.ExecuteScalar附加插入语句

答案 5 :(得分:0)

您的表上是否有可能插入其他表的触发器?一般情况下,我们建议不要使用@@ Identity来支持IDENT_CURRENT,这样就可以保证返回的标识适用于您刚刚插入的表格。

答案 6 :(得分:0)

我认为@@ identity仅在命令范围内有效 - 在您执行“statement”的情况下。

修改“语句”,以便存储过程本身在INSERT语句之后立即返回@@ IDENTITY值,并将其作为存储过程执行的返回码读取。

答案 7 :(得分:0)

检查数据库设置。我不久前遇到过类似的问题,发现SQL Server连接设置“无计数”已启用。

在SQL Server Management Studio中,您可以通过在对象资源管理器中右键单击服务器,选择“属性”,然后导航到“连接”页面来找到它。查看“默认连接选项”

的设置

答案 8 :(得分:0)

大多数回答者都没有忘记提问者没有使用SQL Server吗?

显然,MS Access 2000及更高版本doesn't support @@IDENTITY另一种选择是“使用RowUpdated事件,您可以确定是否发生了INSERT,检索最新的@@ IDENTITY值,以及将它放在DataSet中本地表的标识列中。“

是的,这适用于Access DB中的嵌入式VBA。这仍然可以通过Access对象库在Access之外调用。

编辑:好的,它得到了支持,对于昏昏沉沉的清晨回答感到抱歉。但是这个答案的其余部分可能有所帮助。

答案 9 :(得分:0)

如果您想要检索您正在插入的自动运行的事务数以及您的环境的值   1.数据库是MsAccess。   2.驱动程序是带有连接字符串的Jet4,例如“Provider = Microsoft.Jet.OLEDB.4.0; Password = {0}; Data Source = {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();
}   

答案 10 :(得分:0)

答案简短:
    1.创建两个命令,每个命令接受一个查询     2.第一个sql查询是INSERT记录     3.第二个SQL查询是" SELECT @@ Identity;"返回自动编号     4.使用cmd.ExecuteScalar()返回第一行的第一列     5.返回的结果输出是当前插入查询中生成的AutoNumber值。

It is referenced from this link。示例代码如下。请注意" SAME Con​​nection VS NEW Connection"的区别。 SAME Con​​nection提供所需的输出。

 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

答案 11 :(得分:-1)

当您使用Access时,请查看aspfaq中的this article,向下滚动到页面的大约一半。代码是经典的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”添加到代码末尾的串联。

答案 12 :(得分:-2)

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