一些 ASP.NET + Oracle 11g 系统边写边学的随笔,包括 Oracle 的「ROWNUM」、「Sequence 流水号」。
(六) Oracle 的 ROWNUM,等同其它数据库的 SELECT TOP
Oracle 不支持 SELECT TOP 语法,若要撷取最大的几笔、或最小的几笔记录,必须用 ROWNUM 关键词并搭配 Subquery。
例如要取最小的 10 笔,可用如下语句:
SELECT id, name, ROWNUM FROM (SELECT id, name FROM table ORDER BY id) WHERE ROWNUM <= 10;
若要取最大的 10 笔,就再加上 DESC:
SELECT id, name, ROWNUM FROM (SELECT id, name FROM table ORDER BY id DESC) WHERE ROWNUM <= 10;
此外,还可以做一些变化应用:
SELECT a.id, a.name, ROWNUM FROM (SELECT id, name FROM table ORDER BY id) a WHERE ROWNUM <= 10 ORDER BY ROWNUM DESC;
要注意的是,包含有 ROWNUM 的 WHERE 条件式,一定要包含 1,例如:
WHERE ROWNUM >0
WHERE ROWNUM >=1
WHERE ROWNUM <10
若不包含 1 的话,所下的查询会永远查无数据。
Oracle 的 ROWNUM、Top-N Query 官方教学 (英文):
http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
http://www.oracle.com/technology/oramag/oracle/07-jan/o17asktom.html
此外,Oracle 还有两种 ROW_NUMBER() OVER 和 RANK() OVER 语法,亦可将已查询出来的全部数据,再给予连续的流水号。虽然它们无法像 ROWNUM 一样给 WHERE 条件式,但适
合用来撰写 ASP.NET GridView 控件的「分页」功能的 Stored Procedure。有关其用法,可参考:
http://i.cn.yahoo.com/gaoxiaoqing2003/blog/p_8/
http://keke-wanwei.javaeye.com/blog/138632
(七) Oracle 的 Sequence,等同其它数据库的 Identity
Oracle 不支持 SQL Server 和 Sybase 都支持的 Identity 自动增号字段,也不支持 INSERT INTO 以后立即取得最新一笔记录 Identity 号码的「SELECT @@identity;」语法,
要达成上述功能,必须改用 Sequence (流水号)。
Sequence 不包含在 table 中,某一个 Sequence 亦不和 table 做一对一的对应。要用 Sequence,必须先自己手动建立,语法为:
CREATE SEQUENCE seq_name;
或
CREATE SEQUENCE seq_name
INCREASE BY 1
START WITH 1
MAXVALUE 9999
NOCACHE
NOCYCLE;
若不下参数,预设从 1 开始,每次增号 1,最大值为 10 的 27 次方,存储值达到 MAXVALUE 不会自动重新编号 (若对应至 table 的 Primary Key,此值应采默认值 NOCYCLE);
CACHE 选项的默认值,会在 memory 产生 20 笔数据。
执行以下语句,可看到所有 Sequence 的设定及存储内容。其中的 LAST_NAME 为其下一个将要产生的值。
select * from user_sequences;
要看某一个 Sequence 的当前值、下一个值,可用如下语句:
select table1_seq.CURRVAL from dual;
select table1_se1.NEXTVAL from dual;
需注意第二个语句 NEXTVAL 只要一被执行到,该个 Sequence 的内部编号,就会自动增加一个号码,而不仅只是 select 撷取而已。
若要搭配 Sequence,新增一笔记录到 table,可用如下语法:
INSERT INTO table1 (id, name) VALUES (table1_seq.NEXTVAL, 'name1');
在 Oracle 10g 以前的版本,或您用的是 OleDb 联机方式 (OracleClient 亦可),当您想在 INSERT INTO 记录时,Primary Key 希望能写入 Sequence 的值,可用如下写法 (亦
可在新增完成后,立即传回该笔记录最新的 Sequence 值):
using System.Data.OleDb;
OleDbConnection odConn = null;
OleDbCommand odCmd = null;
Int64 intDATA_ID_AfterInserted = 0;
string strSql = "BEGIN SELECT table1_seq.NEXTVAL INTO :id FROM dual; INSERT INTO table1(id, name) VALUES(:id, :name); END;";
...中间略...
OleDbParameter p;
p = odCmd.Parameters.Add(":id", OleDbType.Double, 7);
p.Direction = ParameterDirection.Output;
odCmd.Parameters.Add(":name", OleDbType.VarWChar, 30).Value = TextBox1.Text;
odCmd.ExecuteNonQuery();
intDATA_ID_AfterInserted = Convert.ToInt64(p.Value); // 立即传回该笔记录最新的 Sequence 值
若您用的是 Oracle 10g 及以后的版本,且用的是 OracleClient Data Provider,则可用以下的「RETURNING INTO」更简洁写法。但须注意,OleDb 联机方式若用此种写法,在写
入时并不会造成 error 或引发 exception,但写入值会不正常。
string strSql = "INSERT INTO table1(id, name) VALUES(table1_seq.NEXTVAL, :name) RETURNING id INTO :id";
---------------------------------------------
本帖第 (七) 点的 ASP.NET 2.0 + Oracle 11g 示例下载点 (批次新增 + 新增后马上取得最新 Sequence 值):
http://files.cnblogs.com/WizardWu/081128.zip
---------------------------------------------
若您执行本示例的操作系统中,并未安装 Oracle 11g server-side 软件 (数据库安装在别台主机),则当您用 Visual Studio 执行本示例时,可能会出现类似以下的错误讯息:
“OraOLEDB.Oracle.1”未在本地计算机注册
解决方式,是去 Oracle 官方网站,下载 Data Provider 和 Client-side 程序并安装,下载网址如下:
http://www.oracle.com/technology/software/tech/windows/odpnet/index.html (较新)
http://www.oracle.com/technology/software/tech/dotnet/utilsoft.html (较旧)
安装完后,即能以 Visual Studio 执行本示例。但若改以 IIS 执行时,仍会出现上述的错误信息,因为您还要再设定一些让 IIS / ASP.NET 的用户,有写入伺服端 Oracle 所在文件夹的权限。有关其设定,其参考本站下一篇帖子「Oracle 11g 学习笔记 (4)」。