C# 为什么返回INTO子句会返回错误?

C# 为什么返回INTO子句会返回错误?,c#,oracle,C#,Oracle,我正在尝试向Oracle数据库表中执行insert并返回新创建的主键(通过触发器和序列) 我有一段代码可以工作。我还有第二段代码返回ExecuteNonQuery()上的错误 在我的一生中,我无法确定为什么第一个代码有效而第二个代码无效 第一个有效的代码是: string sqlStr = @"INSERT INTO LEI_EROUTER_SESSIONS(empCID, JOBNUMBER, EMP_NAME, LOGGEDON, MACHINENAME, IP) value

我正在尝试向Oracle数据库表中执行insert并返回新创建的主键(通过触发器和序列)

我有一段代码可以工作。我还有第二段代码返回ExecuteNonQuery()上的错误

在我的一生中,我无法确定为什么第一个代码有效而第二个代码无效

第一个有效的代码是:

        string sqlStr = @"INSERT INTO LEI_EROUTER_SESSIONS(empCID, JOBNUMBER, EMP_NAME, LOGGEDON, MACHINENAME, IP) values(:empCID, :JOBNUMBER, :EMP_NAME, sysdate, :MACHINENAME, :IP) RETURNING C_ID INTO :LASTCID";

        int C_ID;

        using (RetryClass RetryClassInstance = new RetryClass(CallingForm, JobSessionData, UserData))
        {
            do
            {
                RetryClassInstance.Retry = false;
                C_ID = 0;
                OracleConnection conn = new OracleConnection(Machine_Data.oracle_connstr);
                OracleCommand cmd = new OracleCommand(sqlStr, conn);
                try
                {
                    conn.Open();
                    cmd.Parameters.Add("empCID", UserData.employee_cid);
                    cmd.Parameters.Add("JOBNUMBER", JobSessionData.jobnumber);
                    cmd.Parameters.Add("EMP_NAME", UserData.employee_name);
                    //cmd.Parameters.Add("LOGGEDON", DateTime.Now);
                    cmd.Parameters.Add("MACHINENAME", Environment.MachineName);
                    cmd.Parameters.Add("IP", GlobalFunctions.LocalIPAddress());
                    cmd.Parameters.Add("LASTCID", OracleDbType.Int32, ParameterDirection.Output);
                    cmd.ExecuteNonQuery();

                    C_ID = Convert.ToInt32(cmd.Parameters["LASTCID"].Value.ToString());
                }
                catch (Exception ex)
                {
                    RetryClassInstance.HadException(ex);
                }
                finally
                {
                    if (cmd != null) cmd.Dispose();
                    if (conn != null) conn.Dispose();
                }
            } while (RetryClassInstance.Retry == true);
        }

        return C_ID;
下面是第二段不起作用的代码:

        string C_ID;
        List<string> C_IDS = new List<string>();

        string sqlStr = @"INSERT INTO LEI_CHECKIN_QUEUE(CHECKIN_DATE, JOB_ID, CELL, SN, STEP_NAME, STEP_TYPE, START_SEQ,
                          END_SEQ, CHECKEDINBY_EMP_CID, IN_QUEUE, PRIORITY_CODE, STEP_STARTED_WHEN, GROUP_CID) 
                          VALUES(SYSDATE, :JOB_ID, :CELL, :SN, :STEP_NAME, :STEP_TYPE, :START_SEQ, :END_SEQ, :CHECKEDINBY_EMP_CID, 'Y', null, 
                          null, null) RETURNING C_ID INTO :LASTCID";

        using (RetryClass RetryClassInstance = new RetryClass(this, JobSessionData, UserData))
        {
            do
            {
                RetryClassInstance.Retry = false;
                OracleConnection conn = new OracleConnection(Machine_Data.oracle_connstr);
                OracleCommand cmd = new OracleCommand(sqlStr, conn);
                try
                {
                    conn.Open();

                    foreach (string SN in JobSessionData.serial_numbers)
                    {
                        cmd.Parameters.Clear();
                        cmd.Parameters.Add("JOB_ID", JobSessionData.jobnumber);
                        cmd.Parameters.Add("CELL", JobSessionData.cell);
                        cmd.Parameters.Add("STEP_NAME", StepName);
                        cmd.Parameters.Add("STEP_TYPE", StepType);
                        cmd.Parameters.Add("START_SEQ", Start_Seq);
                        cmd.Parameters.Add("END_SEQ", End_Seq);
                        cmd.Parameters.Add("CHECKEDINBY_EMP_CID", UserData.employee_cid);
                        cmd.Parameters.Add("SN", SN);
                        cmd.Parameters.Add("LASTCID", OracleDbType.Int64, ParameterDirection.Output);

                        cmd.ExecuteNonQuery();

                        C_ID = cmd.Parameters["LASTCID"].Value.ToString();
                        C_IDS.Add(C_ID);
                    }

                }
                catch (Exception ex)
                {
                    RetryClassInstance.HadException(ex);
                }
                finally
                {
                    if (cmd != null) cmd.Dispose();
                    if (conn != null) conn.Dispose();
                }
            } while (RetryClassInstance.Retry == true);
        }
两者都在同一个Oracle数据库实例上运行。如果我注释掉与输出参数相关的行并从SQLINSERT语句中删除returning子句,那么第二段代码就可以正常工作

此外,LEI_CHECKIN_QUEUE表有一个名为C_ID的列,它是主键

有人知道为什么第二段代码不起作用和/或我能做些什么来修复它吗


谢谢

您需要声明变量,如下所示。 根据经验,在将查询嵌入代码之前,请始终在Oracle服务器上测试查询。最重要的是,使用参数化存储过程来避免sql注入攻击。因此,不要在代码中嵌入查询

@"declare   LASTCID number;
INSERT INTO LEI_CHECKIN_QUEUE(CHECKIN_DATE, JOB_ID, CELL, SN, STEP_NAME, STEP_TYPE, START_SEQ,
                          END_SEQ, CHECKEDINBY_EMP_CID, IN_QUEUE, PRIORITY_CODE, STEP_STARTED_WHEN, GROUP_CID) 
                          VALUES(SYSDATE, :JOB_ID, :CELL, :SN, :STEP_NAME, :STEP_TYPE, :START_SEQ, :END_SEQ, :CHECKEDINBY_EMP_CID, 'Y', null, 
                          null, null) RETURNING C_ID INTO :LASTCID";

在我看来,你做了一些额外的不必要的参数

cmd.Parameters.Add("SN", SN);
好习惯是使用“BindByName=true”初始化OracleCommand 差不多

using (OracleCommand countCommand = new OracleCommand(strSql, connection) { CommandType = CommandType.Text, BindByName = true })
{...}
当您在每行中使用“@”时,会将“\n”连接起来,以便生成的字符串

"INSERT INTO LEI_CHECKIN_QUEUE(CHECKIN_DATE, JOB_ID, CELL, SN,  \n STEP_NAME, STEP_TYPE, START_SEQ, END_SEQ, CHECKEDINBY_EMP_CID, \n IN_QUEUE, PRIORITY_CODE, STEP_STARTED_WHEN, GROUP_CID) \n VALUES(SYSDATE, :JOB_ID, :CELL, :SN, :STEP_NAME, :STEP_TYPE, \n :START_SEQ, :END_SEQ, :CHECKEDINBY_EMP_CID, 'Y', null, null, null) \n RETURNING C_ID INTO :LASTCID";
你应该使用

String sql = "INSERT INTO LEI_CHECKIN_QUEUE (CHECKIN_DATE, JOB_ID, CELL, SN, STEP_NAME, STEP_TYPE, START_SEQ,";
sql += "END_SEQ, CHECKEDINBY_EMP_CID, IN_QUEUE, PRIORITY_CODE, STEP_STARTED_WHEN, GROUP_CID)";
sql += "VALUES (SYSDATE,: JOB_ID,: CELL: SN: STEP_NAME,: STEP_TYPE,: START_SEQ,: END_SEQ,: CHECKEDINBY_EMP_CID, 'Y', null,";
sql += "null, null) C_ID RETURNING INTO: LASTCID";
这是一篇老文章,但帮助我解决了问题。我必须更正式一点,使用Oracle.ManagedDataAccess,但本质上我的问题是相同的,在我的情况下,您的查询应该是这样的:

DECLARE
    LASTCID number;
BEGIN
    INSERT INTO LEI_CHECKIN_QUEUE(CHECKIN_DATE, JOB_ID, CELL, SN, STEP_NAME, STEP_TYPE, START_SEQ,
                      END_SEQ, CHECKEDINBY_EMP_CID, IN_QUEUE, PRIORITY_CODE, STEP_STARTED_WHEN, GROUP_CID) 
                      VALUES(SYSDATE, :JOB_ID, :CELL, :SN, :STEP_NAME, :STEP_TYPE, :START_SEQ, :END_SEQ, :CHECKEDINBY_EMP_CID, 'Y', null, 
                      null, null) RETURNING C_ID INTO :LASTCID;
END;

您是否在没有c#代码的情况下直接在Oracle上测试了查询?当我尝试这样做时,我得到以下结果:SQL错误:未注册所有返回参数。我不知道这意味着什么。即使有人能帮助我理解为什么“索引越界”错误与我的代码所做的事情有关,这也会很有帮助。谢谢基本上,您的SQL代码需要在一个块中,并且需要定义返回变量。感谢Grant的编辑。我还在学习!我的第一个代码块运行时没有这样的代码块。我使用的是带返回子句的INSERT语句。您尝试过上述解决方案吗?请告诉我,由于我不愿意相信我以前从未见过的事情,所以我的态度有些僵硬。谢谢Dan Hunex先生有效的回答,这让我非常高兴!我很少寻求帮助,因为我为自己能够解决问题而感到自豪。所以当我发布这个问题时,是因为我真的被卡住了!我已经试了好几个小时让它工作了!谢谢你,丹!现在我可以继续我的项目了!谁能解释一下为什么在这个示例中需要“declare LASTCID number;”才能工作……但我确实有其他示例可以工作,而不必在SQL代码中声明返回参数?我只是遇到了这个问题,我也不知道发生了什么。我对3台应该相同的oracle服务器运行了相同的代码。2在没有声明的情况下工作正常,然后第三个失败,直到我添加它。谢谢你提出这个问题——如果没有这个线程,我会花很长时间进行故障排除。我的参数出了问题,但是SN在查询中……你一定错过了它。对不起,你是对的。但传递参数值的顺序与查询中占位符的顺序不同。更改顺序或使用BindByName=true。我看不出查询文本中有新行的问题,为什么您认为这是个问题?