Sql @@INSERT语句后的标识始终返回0

Sql @@INSERT语句后的标识始终返回0,sql,database,ms-access,primary-key,jet,Sql,Database,Ms Access,Primary Key,Jet,我需要一个函数,它在数据库上执行INSERT语句并返回自动增量主键。我有下面的C代码,但是,虽然INSERT语句工作正常,但我可以在数据库中看到记录,PK生成正确,rows==1,id值始终为0。对可能出现的问题有什么想法吗 public int ExecuteInsertStatement(string statement) { InitializeAndOpenConnection(); int id = -1; IDbCo

我需要一个函数,它在数据库上执行INSERT语句并返回自动增量主键。我有下面的C代码,但是,虽然INSERT语句工作正常,但我可以在数据库中看到记录,PK生成正确,rows==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

我认为您需要在第一个create命令中使用Select@@identity,请尝试通过添加它;选择@@Identity and.ExecuteCalar insert语句

您的表上是否有可能插入到其他表中的触发器?通常,我们建议不要使用@@Identity来支持,这样您就可以保证返回的标识是针对刚刚插入的表的。

我认为@@Identity仅在命令的范围内有效-在您执行语句的情况下


修改语句,使存储过程本身将在INSERT语句之后返回@标识值,并将其作为存储过程执行的返回代码读取。

1使用组合INSERT和SELECT语句连接;转换为1db命令

2使用作用域\标识而不是@标识

插入blabla;从OID=SCOPE\u IDENTITY的表中选择OID

-更新:


由于问题与MS ACCESS有关,我发现这表明,只需重复使用第一个命令并将其CommandText设置为选择@@IDENTITY就足够了。

使用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);
    }
}

您可能希望/需要整理将“选择@@Identity”添加到代码末尾的连接。

您需要在打开初始连接的同时返回标识。 从insert或输出变量返回结果集

您还应始终使用范围\标识而不是@标识

你应该加上

SELECT SCOPE_IDENTITY() 

插入后。

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


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

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

大多数回答者不是都忘记了询问者没有使用SQL Server吗

显然,MS Access 2000及更高版本。另一种方法是使用RowUpdate事件,您可以确定是否发生了插入,检索最新的@IDENTITY值,并将其放置在数据集中本地表的IDENTITY列中

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


编辑:好的,它是受支持的,很抱歉一大早就给出了含糊不清的答案。但是,这个答案的其余部分可能会有所帮助。

Microsoft.Jet.OLEDB.4.0提供程序支持Jet v3和Jet v4数据库引擎 Jet v3不支持选择@标识


MSAccess 97是Jet v3,不支持选择@标识;MSAccess 2000及更高版本支持它。

如果要检索正在插入的事务的自动运行数的值以及您的环境所遵循的值 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();
}   
简单的回答是: 1.创建两个命令,每个命令接受一个查询。 2.第一个sql查询是INSERT记录。 3.第二个sql查询是SELECT@@Identity;返回自动编号。 4.使用cmd.ExecuteScalar返回第一行的第一列。 5.返回的结果输出是在当前插入查询中生成的自动编号值

。示例代码如下所示。注意相同连接与新连接的区别。相同的连接提供所需的输出

 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

我认为您应该使用SCOPE_IDENTITY,因为它返回为当前会话中的任何表生成的最后一个标识值和当前作用域,所以如果它被称为j

ust在向您插入表后,您将保证获得正确的值。使用当前标识,尽管您指定了表名,但不保证它在您的操作范围内,请参阅定义:返回为指定表或视图生成的最后一个标识值。最后生成的标识值可以用于任何会话和任何作用域,我认为这两者都有其缺点。从同一个表中获取另一个标识的机会与从同一范围内的另一个表中获取标识的机会相似。两者都比@Identity.Hi Matt好,如果您调用insert myTable,那么scope_Identity您知道它与myTable有关,并且您保证它在当前范围内。调用IDENT_CURRENT'myTable'时,不能保证作用域在您的控制范围之外。最好有作用域标识'myTable':-不要使用当前标识。我们的一个程序员这样做了,导致数据库中出现了havok,因为并发进程导致相关表包含与错误父级相关的记录。请更改为scope_identity。您能否澄清您正在使用的数据库服务器,并可能内联对InitializeAndOpenConnection/connection.CreateCommand的引用,因为它们可能会影响我们对您的回答另外-整个SELECT OID FROM x,其中OID=SCOPE\u IDENTITY thins有点过于复杂,正如您所说的,对于插入的标识值为3的记录:从表\u x中选择3,其中3=3-有点复杂redundant@Rob:它可能看起来是多余的,但OID的类型是int,而scope_identity不是,因此,您可以直接强制转换intcmd.executescalary您没有使用Access数据库-您使用的是Jet数据库。我想这个问题的最终答案会非常好。整个线程似乎充斥着SQL Server的错误信息和解决方案,而不是Jet引擎。原因是,否则您将发出两个命令,第二个命令知道关于第一个命令的所有信息,所以当您创建了一个标识值时,您并不能从第二个断开连接的命令中获取它。这给了我在SQL语句结束后找到的字符错误只需在第一个语句后使用SELECT SCOPE_标识即可。请参阅下面的链接,以获得对此的良好解释。-1数据库是Jet/ACE,因此此答案完全无效。SQL是一个通用标记。@请看一下历史记录:这些标记是在我的答案之后添加的,所以我更新了我的答案。您的评论可能不是完全无效,但至少晚了3年。Doh,请阅读您使用的是MS Access,而不是SQL Server。不确定我的答案是否适用于MS Access…MS Access 2000及更高版本不支持@@IDENTITY-您的回答是错误的@@仅从MS Access 2000起支持标识。OP称他们使用的是Jet 4.0,这是MS Access 2000首次提供的。大多数回答者都没有忘记——目标数据库引擎是Access这一事实直到给出了相当多的答案后才被提及:故事的寓意是:不要在早上6点回答问题。数据库引擎不是Access,Access不是一个数据库引擎,而是一个数据库应用程序开发平台,附带一个默认的db引擎,即Jet。在遇到同样的问题后,我得出了相同的结论。其他答案中的所有其他解决方案均不适用于Access/Jet。
AutoNumber: 1 <br>
AutoNumber: 2 <br>
AutoNumber: 3 <br>

New connection, AutoNumber: 0