我需要一个在数据库上执行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
答案 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)
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 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
答案 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