几句题外话:
现在越来越觉得数据库的重要作用,程序只是实现这样或那样的业务过程,没有数据库的支撑,程序再怎么写都是鸡肋,特别是大型互联网的应用,数据库绝对是一个重要的方面。
需求背景描述:
在真实的项目中,有这样一个需求:现在有三张数据库表,一张商品信息表productInfo,一张商品定价表productPricing,一张商品整体定价表prodoctUnityPricing。这三张表的表结构如下(注:为了叙述的方便,在此省略了很多字段):
表一:商品信息表productInfo
GD010010001 | LG手机 | 1000.00 | 深圳XX电子 | 10001 |
GD020020002 | 佳能相机 | 2000.00 | 福州XX电子 | 10001 |
GD030040005 | Lenovo ThinkPad | 5500.00 | 联想中国 | 10002 |
该表存储的是商品的相关信息。
表二:商品定价表productPricing
1 | 0001 | GD010010001 | 10001 | 1000.11 |
2 | 0002 | GD010010001 | 10001 | 1577.00 |
3 | 0001 | GD020020002 | 10001 | 2000.22 |
4 | 0001 | GD030040005 | 10002 | 5520.00 |
该表存储的是商品的定价信息,即将商品信息表productInfo的商品重新修订价格之后,会将修改的价格信息存储在该表中。
表三:商品整体定价表prodoctUnityPricing
1 | 0001 | 10001 | 1.00 |
该表存储的是某类商品的整体定价,例如将商品类型productType=10001的商品整体调整价格,使价格统一上浮100元,这种整体价格调整信息将存储在该表中。
业务需求描述:
要处理的问题是从这三张表中获取商品信息,显然,如果只是仅仅查询出商品信息,从商品信息表productInfo查询就够了,但不同的用户他所看到的商品的价格是不一样的。
因此,就出现了下面的几种情况:
1.当商品没有定价(即商品定价表productPricing没有该用户对应的定价记录),并且也没有商品整体定价(即商品整体定价表prodoctUnityPricing没有该用户对应的定价记录),则直接查询商品信息表productInfo中的数据;
2.当商品有定价,但商品没有整体定价,则查询商品信息表productInfo表的数据,但价格是商品定价表productPricing对应的价格,其中当部分商品有定价,部分商品没有定价,则有定价的显示定价价格,无定价的显示商品信息表中的价格;
3当商品有整体定价,但商品没有商品定价,则要将商品信息表的价格都加上整体定价上浮的钱数之后才是最终显示给用户的价格;
4.当商品有定价,并且商品也有整体定价,则优先显示定价的价格。
业务过程如上,该功能也已经上线很久了,但线上的版本使用的是sql查询,sql语句也比较复杂,最近做了一个使用存储过程的版本。
给大家参考的同时也盼望大家看看有没有什么问题呢?
下面是存储过程代码,使用package和package bodies结构:
create or replace package package_productprice is -- Author : hnylj type resultList is ref cursor; procedure processProductPrice(p_userid in varchar2, p_productType in varchar2, p_pageIndex in number, p_pageEnd in number, productList out resultList); end package_productprice;
create or replace package body package_productprice is procedure processProductPrice(p_userid in varchar2, p_productType in varchar2, p_pageIndex in number, p_pageEnd in number, productList out resultList) is --商品整体定价(上浮的钱数) v_productUnityPrice number(8, 2) := 0.00; --判断是否有整体定价 v_count number(1) := 0; begin --查询是否有商品的整体定价 select count(*) into v_count from PRODOCTUNITYPRICING a where a.userid = p_userid and a.producttype = p_productType; --如果不存在整体定价 if v_count = 0 then --查询商品表和商品定价表 open productList for SELECT * FROM (SELECT AA.*, ROWNUM RN FROM (select t.*, p.productPricing from (select a.productid productId, a.productname productName, decode(a.productprice, null, 0.00, a.productprice) productPrice, a.producttype productType from productinfo a where a.producttype = p_productType) t, (select b.productid productId, decode(b.PRODUCPRICING, null, 0.00, b.PRODUCPRICING) productPricing from productpricing b where b.producttype = p_productType and b.userid = p_userid) p where t.productId = p.productId(+) order by t.productPrice) AA WHERE ROWNUM <= p_pageEnd) WHERE RN >= p_pageIndex; end if; --如果存在整体定价 if v_count > 0 then --查询出整体定价上浮的钱数存入v_productUnityPrice变量 select decode(a.unitypricing, null, 0, a.unitypricing) into v_productUnityPrice from PRODOCTUNITYPRICING a where a.userid = p_userid and a.producttype = p_productType; --查询商品表和商品定价表 open productList for SELECT * FROM (SELECT AA.*, ROWNUM RN FROM (select t.*, decode(p.productPricing, null, t.productPrice+v_productUnityPrice, p.productPricing) productPricing from (select a.productid productId, a.productname productName, decode(a.productprice, null, 0.00, a.productprice) productPrice, a.producttype productType from productinfo a where a.producttype = p_productType) t, (select b.productid productId, decode(b.PRODUCPRICING, null, 0.00, b.PRODUCPRICING) productPricing from productpricing b where b.producttype = p_productType and b.userid = p_userid) p where t.productId = p.productId(+) order by t.productPrice) AA WHERE ROWNUM <= p_pageEnd) WHERE RN >= p_pageIndex; --循环游标开始 end if; end processProductPrice; end package_productprice;
存储过程代码如上,使用的动态游标ref cursor。
下面是一段java调用该存储过程的测试代码:
package com.javaeye.hnylj.test; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import com.javaeye.hnylj.model.ProductInfo; /** * 测试存储过程 * * @since Jun 20, 2010 */ public class ProceduresTest { private Connection conn = null; private CallableStatement cstmt = null; private ResultSet rs = null; private static final String DRIVER = "oracle.jdbc.driver.OracleDriver"; private static final String URL = "jdbc:oracle:thin:@127.0.0.1:1521:workdb"; private static final String USERNAME = "framework"; private static final String PASSWORD = "framework"; private List<ProductInfo> list; /** * 数据库连接 * * @return Connection */ public synchronized Connection getConnection() { try { Class.forName(DRIVER); conn = DriverManager.getConnection(URL, USERNAME, PASSWORD); } catch (ClassNotFoundException e) { e.printStackTrace(); return null; } catch (SQLException e) { e.printStackTrace(); return null; } return conn; } /** * 调用存储过程得到游标数据集 * * @return */ public List<ProductInfo> queryList() { list = new ArrayList<ProductInfo>(); try { if (this.getConnection() != null) { conn = this.getConnection(); cstmt = conn.prepareCall("{call package_productprice.processProductPrice(?,?,?,?,?)}"); cstmt.setString(1, "0001"); cstmt.setString(2, "10001"); cstmt.setInt(3, 1); cstmt.setInt(4, 10); cstmt.registerOutParameter(5, oracle.jdbc.OracleTypes.CURSOR); cstmt.execute(); rs = (ResultSet)cstmt.getObject(5); while (rs.next()) { ProductInfo productInfo = new ProductInfo(); productInfo.setProductId(rs.getString(1)); productInfo.setProductName(rs.getString(2)); productInfo.setProductPrice(rs.getDouble(3)); productInfo.setProductType(rs.getString(4)); productInfo.setProductPricing(rs.getDouble(5)); list.add(productInfo); } } } catch (SQLException e) { e.printStackTrace(); } finally { try { if (null != rs) { rs.close(); } if (null != cstmt) { cstmt.close(); } if (null != conn) { conn.close(); } } catch (SQLException e) { e.printStackTrace(); } } return list; } /** * main方法测试 * * @param args * @throws Exception */ public static void main(String[] args) throws Exception { ProceduresTest test = new ProceduresTest(); List<ProductInfo> productList = test.queryList(); for (ProductInfo productInfo : productList) { System.out.println(productInfo.getProductId()); System.out.println(productInfo.getProductName()); System.out.println(productInfo.getProductPrice()); System.out.println(productInfo.getProductPricing()); System.out.println(productInfo.getProductType()); } } }
另外还需要一个model类ProductInfo,该类的代码只要productId、productName、productPrice、productPricing、productType及相应的getter和setter方法。
一个Java技术交流群,一起交流,共同进步,扣扣群号:513086638
相关推荐
- **声明(DECLARE)**:首先,你需要声明一个游标,指定其将绑定的查询语句以及返回的数据类型。 - **打开(OPEN)**:声明完游标后,需要用OPEN语句来初始化并加载数据。 - **提取(FETCH)**:提取操作用于从...
在实际的项目开发中,我们常常需要在一个存储过程中调用另一个返回游标的存储过程,以实现更复杂的业务逻辑。以下将详细讨论如何在Oracle中完成这种调用。 首先,我们来看第一种情况,即返回的游标对应于某个具体的...
函数是另一种在Oracle数据库中使用的编程组件,它可以接受输入参数并返回一个计算结果。 - **特点**: - 可以在SQL语句中调用。 - 必须返回一个值。 - 可以包含复杂的逻辑处理。 - **应用场景**: - 数据验证:...
例如,可以创建一个存储过程,该过程返回一个可滚动的结果集。然后,`JdbcTemplate`会使用`ResultSetExtractor`接口来处理这个结果集。`SplitPageResultSetExtractor`可能就是这样一个自定义的提取器,用于分割结果...
例如,在一个订单处理系统中,可以创建一个触发器,每当有新订单插入时,这个触发器会调用一个存储过程,该过程使用游标遍历订单的每一项商品,检查库存并更新相关记录。这样,系统可以自动跟踪库存变化,无需额外的...
Oracle存储过程返回游标是一种常见的数据处理方式,它允许开发者在存储过程中执行SQL查询并返回结果集,供调用者进一步处理。游标在数据库编程中扮演着重要角色,尤其在处理多行记录时,提供了灵活的数据遍历手段。...
存储过程可以接受参数,返回结果集,甚至能够处理异常。这种封装性使得代码更易于管理和维护,同时减少了网络传输的开销。例如,一个存储过程可能用于处理用户的注册流程,包括验证用户名、密码,插入新用户记录等...
通过分析和学习这个文件,我们可以更深入地了解如何在实际项目中应用游标技术来解决多数据库查询的问题。 总的来说,游标在处理多数据库查询时提供了一种高效且灵活的方法,尤其适用于寻找特定的单条数据。通过熟练...
Oracle游标是数据库管理系统中非常重要的一个概念,它在处理大量数据时提供了高效且灵活的控制方式。在Oracle中,游标(Cursor)允许我们逐行处理查询结果集,而不是一次性加载所有数据,这对于处理复杂的数据操作...
在数据库领域,游标(Cursor)是一种用于处理数据查询结果集的强大工具,尤其在Oracle数据库中,游标的应用极为广泛且功能强大。本文将深入探讨Oracle数据库中游标的基本概念、类型、使用方法以及其在数据处理中的...
Oracle存储过程可以封装复杂的业务逻辑,而游标则用于在结果集上进行迭代,特别是当结果集太大,不适合一次性加载到内存时。下面将详细介绍如何在Java中实现这一功能。 首先,确保你已经在Oracle数据库中创建了包含...
在SQL中,游标允许我们遍历查询返回的结果集,一次处理一行数据,这对于需要按顺序执行某些操作或者逐行检查数据的情况非常有用。 标题“cu.rar_游标”暗示了这个压缩包包含了一个关于SQL游标使用的示例。文件“cu....
“ma5”可能是一个特定项目、工具或代码库的代号,也可能代表某种特定的游标使用模式,比如每5行执行一次操作。然而,由于信息有限,具体的含义需要更多信息来解读。 6. **Ma5压缩包子文件的文件名称列表**: ...
游标在IT行业中,特别是在数据库编程领域,是一个重要的概念。游标允许程序员逐行处理查询结果,这在处理大量数据或者需要多次交互操作时非常有用。以下是对"既简单,又使用的游标实例"的详细解释。 游标,英文名为...
游标在数据库中用于遍历查询结果集,而输出参数则可以用来传递非查询结果的信息。以下是一个简单的Oracle存储过程示例: ```sql CREATE OR REPLACE PROCEDURE get_data ( out_cursor OUT SYS_REFCURSOR, out_...
2. 打开游标:执行查询并创建一个指向结果集的指针。 3. 循环处理:通过提取游标(FETCH)获取当前行数据,进行相应的操作。 4. 关闭游标:处理完所有行后,关闭游标以释放资源。 在Java中调用存储过程返回多行记录...
打开一个记录集,标识号为5,后面操作这个记录集,也要提供这个标识号 -------------------------------------------------------- 关闭记录集 void closeRecordset(int idx = -1); 例: db.closeRecordset(5); 关闭...
Oracle游标是数据库管理系统中非常重要的一个概念,它在处理SQL查询时扮演着核心角色,尤其是在需要逐行处理结果集的场景下。Oracle游标允许我们动态地控制和操作查询的结果,使得我们可以按需处理每一行数据,而不...
在C#中调用Oracle存储过程,我们可以利用OracleCommand对象的ExecuteReader方法,同样可以获取一个游标来处理返回的结果集。 通过详细的性能测试,我们可以找到最佳的游标处理策略,平衡资源消耗和处理速度,优化...