我的ODP.NET开发之路3-ORA-14551: cannot perform a DML operation inside a query

昨天下午写了2个Function,一个是从ERP LN中读出来Item-Purchase BP中的一个指定的Item和BP的BlockingReason,另一个是按照指定的ID从应用系统中读出来Item和BP,从而调用第一个Function返回真正的BlockingReason,在每一个Function中,都有一段如果报错就调用写错误日志的存储过程。在实际的使用中使用:Select Function2(ID) from Dual;,但是老报以下错误:

<br/>ORA-06502: PL/SQL: numeric or value error: character string buffer too small<br/>ORA-06512: at "TROY.ONTRAC_QRS_PKG", line 760<br/>ORA-14551: cannot perform a DML operation inside a query <br/>ORA-06512: at "TROY.COMMON_SYSTEMLOG_PKG", line 43<br/>ORA-06512: at "TROY.COMMON_BAANBRIDGE_PKG", line 339<br/>ORA-01403: no data found <br/>

经过查询,原因是“对数据库有写操作(INSERT、UPDATE、DELETE、CREATE、ALTER、COMMIT)的函数,是无法简单的用SQL来调用的”。按照这篇文章:[URL=http://www.cnblogs.com/pengyq/archive/2008/11/26/1341656.html]ORA-14551: cannot perform a DML operation inside a query [/URL],加上了“自主事务”:PRAGMA AUTONOMOUS_TRANSACTION; ,不过需要注意在Delcare的部分加入“PRAGMA AUTONOMOUS_TRANSACTION;”之后,必须在SQL语句后面加入“COMMIT;”

看如下例子:

<br/>    /*/* RFD #50 20111214 new start Troy Cui */<br/>    PRAGMA AUTONOMOUS_TRANSACTION;<br/>    /*/* RFD #50 20111214 new end Troy Cui */<br/>    BEGIN<br/>    <br/>        select trim(nvl(FirstName, '') || ' ' || nvl(LastName, ''))<br/>          into sDisplayName<br/>          from COMMON_Users<br/>         where UserID = nLoggedByID;<br/><br/>        if (sDisplayName = '') then <br/>            sDisplayName := '- unassigned -';<br/>        end if;<br/>    <br/>        insert into COMMON_SystemLog(LoggedByID, LogDate, LogCategory, LogEntry, AccessLevel, <br/>                                     Source, DataDump, DisplayName)<br/>                              values(nLoggedByID, SYSTIMESTAMP, sLogCategory, sLogEntry, nAccessLevel,<br/>                                     sSource, sDataDump, sDisplayName);<br/>        /*/* RFD #50 20111214 new start Troy Cui */<br/>        COMMIT;<br/>        /*/* RFD #50 20111214 new end Troy Cui */<br/><br/>    END WriteLog;<br/>

Loading

我的ODP.NET开发之路3-Oracle Package/Procedure/Function

上周的项目进展比较大,完成了几个重大的功能。这其中涉及到在Oracle中创建新表、序列、索引、触发器、包、存储过程、函数,当然了也在实战中学习了几个.Net的Dataset\Datatable的用法。一直想写,不过项目紧,真没空。这不今天有点时间,但是很多东西又没那么强烈的书写欲望了。

说说今天工作遇到的几个东东吧,第一个是Oracle中的包。不晓得为什么Oracle设计包,并且把存储过程和函数都写在不同的包里,而MSSQL虽然也都有存储过程和函数,但是基本上所有的C#程序调用都是对存储过程的操作。Oracle中的存储过程如果放在包内,C#程序使用“包名.存储过程(变量)”或者“包名.函数(变量)”的形式来访问。

对于创建或者修改包的语法我就不重复了,你可以搜索一下。不过有一点我需要分享给大家,在Function中,如果对变量赋值,写法可不一样。

MSSQL中一般写成

<br/>@BlockingReason nvarchar(50)<br/><br/>Select @BlockingReason = value from table where ...<br/>

而在Oracle中是Select value into variable from table where …,看下面的例子

<br/>BlockingReason   varchar2(100);<br/>select trim(nvl(ipbp.t$brea,'')) into BlockingReason<br/>               from baan.ttdipu010301 ipbp  -- item - purchase BP data<br/>              where upper(trim(ipbp.t$item)) = upper(sWAIPartNumber)<br/>                and ipbp.t$otbp =  upper(sBusinessPartnerCode)<br/>                and rownum <=1 order by rownum;<br/>

第二个要分享的是3个很有用的Oracle函数:SUBSTR、DECODE、NVL
SUBSTR(Value,1,5) 取出从Value的第1位开始取5个字符长度
NVL(Value,’a’) 如果Value为Null返回a
DECODE比较复杂,如果你需要针对一个值做很多判断的时候,不用写case了。这个详细的介绍和用法,你搜索一下吧,我解释不清楚。

第三个要分享的,其实是C# .Net的一个Datatable绑定到Dropdownlist的代码,包括了选择值的默认选项

<br/>WAIonTracFailureModes oFailureModes = new WAIonTracFailureModes(_oWorkItem.ApplicationID);<br/><br/>        DataTable dt = oFailureModes.List().Tables[0].Copy();<br/>        DataRow[] drs = dt.Select("ParentID=0");<br/>        foreach (DataRow r in drs)<br/>        {<br/>            //text,value<br/>            WAIonTracFailureModeList.Items.Add(new ListItem(r["Name"].ToString(), r["FailureModeID"].ToString()));<br/>        }<br/><br/>        //WAIonTracFailureModeList.DataSource = oFailureModes.List();<br/>        //WAIonTracFailureModeList.DataTextField = "Name";<br/>        //WAIonTracFailureModeList.DataValueField = "FailureModeID";<br/>        //WAIonTracFailureModeList.DataBind();<br/><br/>        //DataRow[] drs2 = dt.Select("ParentID="+_oWorkItem.FailureModeID);<br/>        DataTable dt2 = oFailureModes.List().Tables[0].Copy();<br/>        DataRow[] drs2 = dt2.Select();<br/>        //<br/>        if (_oWorkItem.FailureModeID != null)<br/>        {<br/>            drs2 = dt2.Select("ParentID=" + _oWorkItem.FailureModeID);<br/>        }<br/><br/>        foreach (DataRow r2 in drs2)<br/>        {<br/>            //text,value<br/>            WAIonTracDetailsOfFailureList.Items.Add(new ListItem(r2["Name"].ToString(), r2["FailureModeID"].ToString()));<br/>        }<br/>

绑定默认/选择值的

<br/>WAIonTracFailureModeList.SelectedIndex = WAIonTracFailureModeList.Items.IndexOf(WAIonTracFailureModeList.Items.FindByValue(_oWorkItem.FailureModeID.ToString()));<br/>        WAIonTracDetailsOfFailureList.SelectedIndex = WAIonTracDetailsOfFailureList.Items.IndexOf(WAIonTracDetailsOfFailureList.Items.FindByValue(_oWorkItem.DetailsOfFailureID.ToString()));<br/>

先写这么多吧,比较乱。另外,昨天买的《涂抹Oracle-三思笔记之一步一步学Oracle》已经到手,目前只知道如何用了,但是“为什么”还不知道,希望这本评价颇高的书能告诉我。

Loading

我的ODP.NET开发之路1

从Oracle下载了ODTwithODAC112021.zip的安装文件,是Oracle11g的,因为本来电脑上安装了Oracle 10g的客户端,所以在安装的时候走了一些弯路,后来把Oracle 10g的客户端删掉,接着把ODP.NET也删掉,重启电脑重新安装ODP.NET,然后在默认的C:\app\你的登陆账号\product\11.2.0\client_1\Network\Admin下放置正确的tnsnames.ora文件。打开VS2010后,就能顺利连接Oracle了。

Loading