今天用到C#里调用Oralce包里的SP返回分页的记录集,在网上查了一下,都用的是MS提供的Oracle.Cient,而在Oracle.DataAccess.Client 里调用时(Ms的Oracle.Client 有问题,所以用的是Oracle官方提供的Oracle.DataAccess.Client ), 输出的参数也要赋值后调用才能返回,否则返回的记录集是空的。即DbNull.Value要先赋值到参数上。本人用Oracle还不到三个星期,因此肯定有不对的地方,还望各位大虾们多多指教。
今天发现Oracle的Package确实不错,是我用的这几天里的我目前感觉到的一大亮点(可以重载,可以把相关的操作放到一个包里)。不知MSSQL2008里有没有。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
闲话少说,上代码:
C#里调用的代码如下:
1
[Test]
2 public void Page1Test()
3 {
4 using(Database db = DBFactory.Create())
5 {
6 const string sql = " select * from test_temp where ID < 1000 order by id asc ";
7
8 OracleCommand cmd = new OracleCommand("PAGESPLIT_PKG.PAGESPLIT_SP",db.Connection);
9 cmd.CommandType = CommandType.StoredProcedure;
10 OracleParameter p1 = new OracleParameter("pagesize", OracleDbType.Int32);
11 p1.Direction = ParameterDirection.Input;
12 p1.Value = 20;
13 OracleParameter p2 = new OracleParameter("pageindex", OracleDbType.Int32);
14 p2.Direction = ParameterDirection.Input;
15 p2.Value = 2;
16 OracleParameter p3 = new OracleParameter("sqltext", OracleDbType.Varchar2);
17 p3.Direction = ParameterDirection.Input;
18 p3.Value = sql;
19
20 OracleParameter p4 = new OracleParameter("Records_out", OracleDbType.Int32,DBNull.Value,ParameterDirection.Output); //就算是空值也要写,否则是会出错的
21 OracleParameter p5 = new OracleParameter("table_out", OracleDbType.RefCursor,DBNull.Value, ParameterDirection.Output);
22
23 cmd.Parameters.Add(p1);
24 cmd.Parameters.Add(p2);
25 cmd.Parameters.Add(p3);
26 cmd.Parameters.Add(p4);
27 cmd.Parameters.Add(p5);
28
29 OracleDataAdapter da = new OracleDataAdapter(cmd);
30
31
32 DataSet ds = new DataSet();
33 da.Fill(ds);
34
35 Console.WriteLine(ds.Tables.Count);
36 Console.WriteLine(ds.Tables[0].TableName);
37 Console.WriteLine(ds.Tables[0].Rows.Count);
38 Console.WriteLine("结果:" + cmd.Parameters["Records_out"].Value.ToString());
39
40 foreach(DataRow row in ds.Tables[0].Rows)
41 {
42 Console.WriteLine(row[1]);
43 }
44 }
45 }
46
2 public void Page1Test()
3 {
4 using(Database db = DBFactory.Create())
5 {
6 const string sql = " select * from test_temp where ID < 1000 order by id asc ";
7
8 OracleCommand cmd = new OracleCommand("PAGESPLIT_PKG.PAGESPLIT_SP",db.Connection);
9 cmd.CommandType = CommandType.StoredProcedure;
10 OracleParameter p1 = new OracleParameter("pagesize", OracleDbType.Int32);
11 p1.Direction = ParameterDirection.Input;
12 p1.Value = 20;
13 OracleParameter p2 = new OracleParameter("pageindex", OracleDbType.Int32);
14 p2.Direction = ParameterDirection.Input;
15 p2.Value = 2;
16 OracleParameter p3 = new OracleParameter("sqltext", OracleDbType.Varchar2);
17 p3.Direction = ParameterDirection.Input;
18 p3.Value = sql;
19
20 OracleParameter p4 = new OracleParameter("Records_out", OracleDbType.Int32,DBNull.Value,ParameterDirection.Output); //就算是空值也要写,否则是会出错的
21 OracleParameter p5 = new OracleParameter("table_out", OracleDbType.RefCursor,DBNull.Value, ParameterDirection.Output);
22
23 cmd.Parameters.Add(p1);
24 cmd.Parameters.Add(p2);
25 cmd.Parameters.Add(p3);
26 cmd.Parameters.Add(p4);
27 cmd.Parameters.Add(p5);
28
29 OracleDataAdapter da = new OracleDataAdapter(cmd);
30
31
32 DataSet ds = new DataSet();
33 da.Fill(ds);
34
35 Console.WriteLine(ds.Tables.Count);
36 Console.WriteLine(ds.Tables[0].TableName);
37 Console.WriteLine(ds.Tables[0].Rows.Count);
38 Console.WriteLine("结果:" + cmd.Parameters["Records_out"].Value.ToString());
39
40 foreach(DataRow row in ds.Tables[0].Rows)
41 {
42 Console.WriteLine(row[1]);
43 }
44 }
45 }
46
Oracle里分页包代码如下:
1
create
or
replace
package PageSplit_PKG
as
2 -- ---------------------------------------------------------------------
3 -- 分页模块PageSplitPackage4Oracle V0.01
4 -- Author : zhouyu Eamil:atwind@cszi.com
5 -- 2009-11-4
6 -- ---------------------------------------------------------------------/
7
8 type DataTable is REF CURSOR ; -- 游标类型定义,用于返回数据集
9
10 procedure PageSplit_SP(PageSize int ,PageIndex int ,SqlText string,Records_out out int ,Table_out out DataTable); -- 申明包里的SP1
11
12 procedure PageSplit_SP(PageSize int ,PageIndex int ,SqlText string,Records_out out int ,Pages_out out int ,Table_out out DataTable); -- 申明包里的SP2
13
14 procedure PageSplit_SP(PageSize int ,PageIndex int ,SqlText string,SqlTextCount string,Records_out out int ,Table_out out DataTable); -- 申明包里的SP3
15
16 procedure PageSplit_SP(PageSize int ,PageIndex int ,SqlText string,Table_out out DataTable); -- 申明包里的SP3
17
18 end ;
19
20 create or replace package body PageSplit_PKG as
21
22 -- 以下方法来自于网络修改
23 -- ------------------------------------------------------------------------------------------
24 -- 功能描述: 大数据量分页通用存储过程,超过100W数据的表,尽量加上索引上的条件
25 -- 创建时间: 2009-11-4
26 -- ------------------------------------------------------------------------------------------/
27 procedure PageSplit_SP
28 (
29 PageSize int , -- 每页记录数
30 PageIndex int , -- 当前页码,从 1 开始
31 SqlText string, -- 查询语句,含排序部分
32 Records_out out int , -- 返回总记录数
33 Table_out out DataTable -- --返回当前页数据记录
34 ) as -- 对包中定义的SP1的实现
35 v_sql varchar2 ( 8000 ); -- 不要超过32767个字符,不可以使用nvarchar2型,下面用的是to_char()
36 v_count int ;
37 v_maxRownum int ;
38 v_minRownum int ;
39 begin
40 -- 取记录总数
41 v_sql : = ' select count(*) from ( ' || SqlText || ' ) ' ; -- 拼接统计Sql
42 execute immediate v_sql into v_count; -- 执行统计
43 Records_out : = v_count;
44
45 -- 行位置判断
46 v_maxRownum : = PageIndex * PageSize;
47 v_minRownum : = v_maxRownum - PageSize + 1 ;
48
49 -- 拼接查询语句
50 v_sql : = ' SELECT *
51 FROM (
52 SELECT A.*, rownum rn
53 FROM ( ' || SqlText || ' ) A
54 WHERE rownum <= ' || to_char(v_maxRownum) || '
55 ) B
56 WHERE rn >= ' || to_char(v_minRownum) ;
57 -- 注意对rownum别名的使用,第一次直接用rownum,第二次一定要用别名rn
58
59 open Table_out for v_sql;
60
61 end ;
62
63
64 /*****************************************************************
65 *功能描述: 大数据量分页通用存储过程(重载1,直接返回分页数量)
66 *创建时间: 2009-11-3
67 *****************************************************************/
68 procedure PageSplit_SP
69 (
70 PageSize int , -- 每页记录数
71 PageIndex int , -- 当前页码,从 1 开始
72 SqlText string, -- 查询语句,含排序部分
73 Records_out out int , -- 返回总记录数
74 Pages_out out int , -- 返回分出的页数
75 Table_out out DataTable -- --返回当前页数据记录
76 )
77 as
78 v_sql varchar2 ( 8000 );
79 v_count int ;
80 v_maxRownum int ;
81 v_minRownum int ;
82 begin
83 -- --取记录总数
84 v_sql : = ' select count(*) from ( ' || SqlText || ' ) ' ; -- 生成统计字符串
85 execute immediate v_sql into v_count; -- 执行统计
86 Records_out : = v_count;
87
88 -- 行位置判断
89 v_maxRownum : = PageIndex * PageSize;
90 v_minRownum : = v_maxRownum - PageSize + 1 ;
91
92 -- 拼接查询语句
93 v_sql : = ' SELECT *
94 FROM (
95 SELECT A.*, rownum rn
96 FROM ( ' || SqlText || ' ) A
97 WHERE rownum <= ' || to_char(v_maxRownum) || '
98 ) B
99 WHERE rn >= ' || to_char(v_minRownum) ;
100 -- 注意对rownum别名的使用,第一次直接用rownum,第二次一定要用别名rn
101
102 OPEN Table_out FOR v_sql;
103
104 end ;
105
106
107 /*****************************************************************
108 *功能描述: 大数据量分页通用存储过程(重载2,自定义统计查询,推荐使用)
109 *创建时间: 2009-11-3
110 *****************************************************************/
111 procedure PageSplit_SP
112 (
113 PageSize int , -- 每页记录数
114 PageIndex int , -- 当前页码,从 1 开始
115 SqlText string, -- 查询语句,含排序部分
116 SqlTextCount string, -- 获取记录总数的查询语句
117 Records_out out int , -- 返回总记录数
118 Table_out out DataTable)
119 as
120 v_sql varchar2 ( 8000 );
121 v_count int ;
122 v_maxRownum int ;
123 v_minRownum int ;
124 begin
125 -- --取记录总数
126 execute immediate SqlTextCount into v_count;
127 Records_out : = v_count;
128 -- --执行分页查询
129 v_maxRownum : = PageIndex * PageSize;
130 v_minRownum : = v_maxRownum - PageSize + 1 ;
131
132 v_sql : = ' SELECT *
133 FROM (
134 SELECT A.*, rownum rn
135 FROM ( ' || SqlText || ' ) A
136 WHERE rownum <= ' || to_char(v_maxRownum) || '
137 ) B
138 WHERE rn >= ' || to_char(v_minRownum) ;
139 -- 注意对rownum别名的使用,第一次直接用rownum,第二次一定要用别名rn
140
141 OPEN Table_out FOR v_sql;
142
143 end ;
144
145 /*****************************************************************
146 *功能描述: 大数据量分页通用存储过程(重载3,不输出总记录数,适用于外部分页计算,内部直选记录集,DB计算压力最小)
147 *创建时间: 2009-11-3
148 *****************************************************************/
149 procedure PageSplit_SP
150 (
151 PageSize int , -- 每页记录数
152 PageIndex int , -- 当前页码,从 1 开始
153 SqlText string, -- 查询语句,含排序部分
154 Table_out out DataTable
155 )
156 as
157 v_sql varchar2 ( 8000 );
158 v_maxRownum int ;
159 v_minRownum int ;
160 begin
161
162 -- --执行分页查询
163 v_maxRownum : = PageIndex * PageSize;
164 v_minRownum : = v_maxRownum - PageSize + 1 ;
165
166 v_sql : = ' SELECT *
167 FROM (
168 SELECT A.*, rownum rn
169 FROM ( ' || SqlText || ' ) A
170 WHERE rownum <= ' || to_char(v_maxRownum) || '
171 ) B
172 WHERE rn >= ' || to_char(v_minRownum) ;
173 -- 注意对rownum别名的使用,第一次直接用rownum,第二次一定要用别名rn
174
175 OPEN Table_out FOR v_sql;
176
177 end ;
178
179
180 end ;
181
2 -- ---------------------------------------------------------------------
3 -- 分页模块PageSplitPackage4Oracle V0.01
4 -- Author : zhouyu Eamil:atwind@cszi.com
5 -- 2009-11-4
6 -- ---------------------------------------------------------------------/
7
8 type DataTable is REF CURSOR ; -- 游标类型定义,用于返回数据集
9
10 procedure PageSplit_SP(PageSize int ,PageIndex int ,SqlText string,Records_out out int ,Table_out out DataTable); -- 申明包里的SP1
11
12 procedure PageSplit_SP(PageSize int ,PageIndex int ,SqlText string,Records_out out int ,Pages_out out int ,Table_out out DataTable); -- 申明包里的SP2
13
14 procedure PageSplit_SP(PageSize int ,PageIndex int ,SqlText string,SqlTextCount string,Records_out out int ,Table_out out DataTable); -- 申明包里的SP3
15
16 procedure PageSplit_SP(PageSize int ,PageIndex int ,SqlText string,Table_out out DataTable); -- 申明包里的SP3
17
18 end ;
19
20 create or replace package body PageSplit_PKG as
21
22 -- 以下方法来自于网络修改
23 -- ------------------------------------------------------------------------------------------
24 -- 功能描述: 大数据量分页通用存储过程,超过100W数据的表,尽量加上索引上的条件
25 -- 创建时间: 2009-11-4
26 -- ------------------------------------------------------------------------------------------/
27 procedure PageSplit_SP
28 (
29 PageSize int , -- 每页记录数
30 PageIndex int , -- 当前页码,从 1 开始
31 SqlText string, -- 查询语句,含排序部分
32 Records_out out int , -- 返回总记录数
33 Table_out out DataTable -- --返回当前页数据记录
34 ) as -- 对包中定义的SP1的实现
35 v_sql varchar2 ( 8000 ); -- 不要超过32767个字符,不可以使用nvarchar2型,下面用的是to_char()
36 v_count int ;
37 v_maxRownum int ;
38 v_minRownum int ;
39 begin
40 -- 取记录总数
41 v_sql : = ' select count(*) from ( ' || SqlText || ' ) ' ; -- 拼接统计Sql
42 execute immediate v_sql into v_count; -- 执行统计
43 Records_out : = v_count;
44
45 -- 行位置判断
46 v_maxRownum : = PageIndex * PageSize;
47 v_minRownum : = v_maxRownum - PageSize + 1 ;
48
49 -- 拼接查询语句
50 v_sql : = ' SELECT *
51 FROM (
52 SELECT A.*, rownum rn
53 FROM ( ' || SqlText || ' ) A
54 WHERE rownum <= ' || to_char(v_maxRownum) || '
55 ) B
56 WHERE rn >= ' || to_char(v_minRownum) ;
57 -- 注意对rownum别名的使用,第一次直接用rownum,第二次一定要用别名rn
58
59 open Table_out for v_sql;
60
61 end ;
62
63
64 /*****************************************************************
65 *功能描述: 大数据量分页通用存储过程(重载1,直接返回分页数量)
66 *创建时间: 2009-11-3
67 *****************************************************************/
68 procedure PageSplit_SP
69 (
70 PageSize int , -- 每页记录数
71 PageIndex int , -- 当前页码,从 1 开始
72 SqlText string, -- 查询语句,含排序部分
73 Records_out out int , -- 返回总记录数
74 Pages_out out int , -- 返回分出的页数
75 Table_out out DataTable -- --返回当前页数据记录
76 )
77 as
78 v_sql varchar2 ( 8000 );
79 v_count int ;
80 v_maxRownum int ;
81 v_minRownum int ;
82 begin
83 -- --取记录总数
84 v_sql : = ' select count(*) from ( ' || SqlText || ' ) ' ; -- 生成统计字符串
85 execute immediate v_sql into v_count; -- 执行统计
86 Records_out : = v_count;
87
88 -- 行位置判断
89 v_maxRownum : = PageIndex * PageSize;
90 v_minRownum : = v_maxRownum - PageSize + 1 ;
91
92 -- 拼接查询语句
93 v_sql : = ' SELECT *
94 FROM (
95 SELECT A.*, rownum rn
96 FROM ( ' || SqlText || ' ) A
97 WHERE rownum <= ' || to_char(v_maxRownum) || '
98 ) B
99 WHERE rn >= ' || to_char(v_minRownum) ;
100 -- 注意对rownum别名的使用,第一次直接用rownum,第二次一定要用别名rn
101
102 OPEN Table_out FOR v_sql;
103
104 end ;
105
106
107 /*****************************************************************
108 *功能描述: 大数据量分页通用存储过程(重载2,自定义统计查询,推荐使用)
109 *创建时间: 2009-11-3
110 *****************************************************************/
111 procedure PageSplit_SP
112 (
113 PageSize int , -- 每页记录数
114 PageIndex int , -- 当前页码,从 1 开始
115 SqlText string, -- 查询语句,含排序部分
116 SqlTextCount string, -- 获取记录总数的查询语句
117 Records_out out int , -- 返回总记录数
118 Table_out out DataTable)
119 as
120 v_sql varchar2 ( 8000 );
121 v_count int ;
122 v_maxRownum int ;
123 v_minRownum int ;
124 begin
125 -- --取记录总数
126 execute immediate SqlTextCount into v_count;
127 Records_out : = v_count;
128 -- --执行分页查询
129 v_maxRownum : = PageIndex * PageSize;
130 v_minRownum : = v_maxRownum - PageSize + 1 ;
131
132 v_sql : = ' SELECT *
133 FROM (
134 SELECT A.*, rownum rn
135 FROM ( ' || SqlText || ' ) A
136 WHERE rownum <= ' || to_char(v_maxRownum) || '
137 ) B
138 WHERE rn >= ' || to_char(v_minRownum) ;
139 -- 注意对rownum别名的使用,第一次直接用rownum,第二次一定要用别名rn
140
141 OPEN Table_out FOR v_sql;
142
143 end ;
144
145 /*****************************************************************
146 *功能描述: 大数据量分页通用存储过程(重载3,不输出总记录数,适用于外部分页计算,内部直选记录集,DB计算压力最小)
147 *创建时间: 2009-11-3
148 *****************************************************************/
149 procedure PageSplit_SP
150 (
151 PageSize int , -- 每页记录数
152 PageIndex int , -- 当前页码,从 1 开始
153 SqlText string, -- 查询语句,含排序部分
154 Table_out out DataTable
155 )
156 as
157 v_sql varchar2 ( 8000 );
158 v_maxRownum int ;
159 v_minRownum int ;
160 begin
161
162 -- --执行分页查询
163 v_maxRownum : = PageIndex * PageSize;
164 v_minRownum : = v_maxRownum - PageSize + 1 ;
165
166 v_sql : = ' SELECT *
167 FROM (
168 SELECT A.*, rownum rn
169 FROM ( ' || SqlText || ' ) A
170 WHERE rownum <= ' || to_char(v_maxRownum) || '
171 ) B
172 WHERE rn >= ' || to_char(v_minRownum) ;
173 -- 注意对rownum别名的使用,第一次直接用rownum,第二次一定要用别名rn
174
175 OPEN Table_out FOR v_sql;
176
177 end ;
178
179
180 end ;
181
这儿有个怪问题,就是在Toad里编译能通过,PLSQL Developer里则有问题。不知啥原因!