@@ IDENTITY INSERT语句总是返回0
我需要一个函数,它在数据库上执行INSERT语句并返回Auto_Increment主键。我有下面的C#代码,但是,虽然INSERT语句正常工作(我可以看到数据库中的记录,PK生成正确,行数为1),但id值始终为0.关于可能发生什么的任何想法错误?@@ IDENTITY INSERT语句总是返回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连接,提供程序= Microsoft.Jet.OLEDB.4.0
我认为你需要有与第一个创建命令选择@@身份 - 尝试追加它通过“; SELECT @@身份”和.ExecuteScalar theinsert语句
是否有你的表可能会被插入到其他表的触发器?通常我们建议不要使用@@ Identity来支持IDENT_CURRENT,这样您就可以保证返回的身份是针对您刚插入的表格。
我想你应该使用SCOPE_IDENTITY,因为它返回当前会话和当前作用域中任何表生成的最后一个标识值,因此如果在插入表格后立即调用它,则可以保证获得正确的值。 – kristof 2008-10-09 09:57:07
使用IDENT_CURRENT虽然指定了表名称,但不保证它在您的操作范围内,请参阅定义:“返回为指定的表或视图生成的最后一个标识值。生成的最后一个标识值可用于任何会话和任何范围“ – kristof 2008-10-09 09:58:37
我认为要么有其缺点。从同一个表中获取“另一个”身份的机会与从同一个范围内的另一个表中获取身份类似。要么比@@身份好。 – 2008-10-09 10:35:07
我认为@@身份只有在命令的范围内是有效的 - 在你的情况,当你执行“声明”。
修改你的“声明”,让存储过程本身将在INSERT语句之后返回@@ IDENTITY值,并把它读作执行存储过程的返回码。
1)相结合的INSERT和SELECT语句(串联使用 “;”)到1分贝命令
2)使用SCOPE_IDENTITY()代替@@ IDENTITY
INSERT INTO ...布拉布拉; SELECT OID FROM表WHERE OID = SCOPE_IDENTITY()
- 更新:
因为它变成了该问题涉及到MS Access,我发现this article这表明简单地再次将第一命令和设定其CommandText到“SELECT @@ IDENTITY”就足够了。
当你使用访问,看看this article从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 @@身份”到代码末端的串联。
你需要在同一时间,因为你打开初始连接返回身份。 从插入或输出变量中返回结果集。
你也应该使用SCOPE_IDENTITY()不@@的身份。Reference here
您应该添加
SELECT SCOPE_IDENTITY()
插入之后。
检查您的数据库设置。我前段时间遇到类似问题,并发现SQL Server连接设置'no count'已启用。
在SQL Server Management Studio中,您可以通过右键单击对象资源管理器中的服务器,选择属性然后导航到连接页面来找到它。查看“默认连接选项”的设置
您正在使用Jet(不是SQL Server),Jet每个命令只能处理一条SQL语句,因此您需要在单独的命令中执行SELECT @@IDENTITY
,显然确保它使用与INSERT
相同的连接。
是不是大多数回答者忘记提问者没有使用SQL Server?
显然,MS Access 2000及更高版本
doesn't support @@IDENTITY。
另一种方法是“使用RowUpdated事件,您可以确定是否发生了INSERT,检索最新的@@ IDENTITY值,并将其放入DataSet中本地表的标识列中。”
是的,这是针对Access DB中的嵌入式VBA。这仍然可以通过访问对象库进行调用。
编辑:好吧,它是支持的,对于昏昏欲睡的清晨答案抱歉。但这个答案的其余部分可能会有所帮助。
Microsoft.Jet.OLEDB.4.0提供程序支持Jet v3和Jet v4数据库引擎,但 Jet @ v3不支持SELECT @@ IDENTITY。
MSAccess 97是Jet v3,不支持SELECT @@ IDENTITY;它支持MSAccess 2000及以上版本。
如果您想要检索您插入的交易的自动运行次数和您的环境的价值,请登录 1.数据库为MsAccess。 2.驱动是Jet4与这样的连接字符串 “提供者= Microsoft.Jet.OLEDB.4.0;密码= {0};数据源= {1};坚持安全信息=真” 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();
}
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
简短的回答:
1.创建每接受一个查询两个命令。
2.首先sql查询是INSERT记录。
3.第二个sql查询是“SELECT @@ Identity;”它返回自动编号。
4.使用cmd.ExecuteScalar()返回第一行的第一列。
5.返回的结果输出是在当前插入查询中生成的自动编号值。
It is referenced from this link。示例代码如下。请注意“SAME连接VS新连接”的区别。 SAME连接提供所需的输出。
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
你能澄清你正在使用的数据库服务器,并可能对内嵌InitializeAndOpenConnection/connection.CreateCommand引用,因为它们可能会影响我们的答案您? :) – Rob 2008-10-09 10:00:54
此外 - 整个“选择OID从x其中OID = SCOPE_IDENTITY()”瘦有点过于复杂,你说的(对于插入身份值为3的记录):“SELECT 3 FROM table_x WHERE 3 = 3“ - 有点多余 – Rob 2008-10-09 10:02:21
@Rob:它可能看起来多余,但OID是键入int,其中scope_identity()不是,所以你可以直接抛出(int)cmd.ExecuteScalar() – devio 2008-10-09 13:03:50