结合于Spring和Ibatis的实际运用我写了一个例子,例子中实现了一个简单的登录过程和一个订货单的主从表形式的增、删、改、查功能,以供大家参考。
我使用了Spring中的AbstractController控制器作为整个程序的基本的控制器,之所以这样做是考虑到简单实用的目的,同时能够实现主从表形式的数据输入,对于事务管理直接用ibatis中提供的事务管理功能,jsp页面统一存放在WEB-INF\view\下面,这样可以防止用户直接通过地址栏来访问jsp页面,jsp页面上用到的js脚本都以js文件的形式include到页面中,对于页面上的数据都以jstl的标签来输出达到页面简洁的目的。
配置文件说明
/WEB-INF/web.xml文件
程序运行的主要配置文件,配置了各种系统变量,对spring的加载,日志的加载等等
/WEB-INF/applicationContext.xml文件
启动时由spring加载系统中用到的各种bean
/WEB-INF/main-config.xml文件
对系统管理模块中的请求/处理单元的配置
/WEB-INF/indent-config.xml文件
对订货单模块中的请求/处理单元的配置
/WEB-INF/sqlMapConfig.xml文件
Ibatis的核心配置文件
WEB-INF\classes\com\ user.xml文件
用户模块的sql语句的映射文件
WEB-INF\classes\com\ common.xml文件
公用模块的sql语句的映射文件
WEB-INF\classes\com\ indent.xml文件
订货单模块的映射文件
对于系统中用到的控制器,我首先对AbstractController进行了抽象,编写了SimpleController类,在SimpleController类中我加入了各控制器中都要用到的公用属性和公用的bean,并抽象出AbstractController的
public abstract ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception;方法
其它各模块则继承自SimpleController,实现该方法,这样就可以使用SimpleController类中的各种属性和方法。
程序运行的具体流程如下
首先访问站点的入口web/index.jsp文件
<%@ include file="/WEB-INF/view/inc/head.jsp" %> <%-- Redirected because we can't set the welcome page to a virtual URL. --%>
<c:redirect url="/loginInit.do"/> |
文件中首先include了对jstl标签库的引用/WEB-INF/view/inc/head.jsp文件
<%@ page session="true"%> <%@ taglib prefix="spring" uri="/WEB-INF/spring.tld"%> <%@ taglib prefix="c" uri="/WEB-INF/c.tld" %> <%@ taglib prefix="fmt" uri="/WEB-INF/fmt.tld" %> |
<c:redirect url="/loginInit.do"/>标签是重定向标签,该标签发出请求动作/loginInit.do到web容器,web容器依据web.xml中定义的请求映射动作
<servlet-mapping> <servlet-name>main</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> |
将该动作交由main所定义的系统管理模块的引擎进行调度
<servlet> <servlet-name>main</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/main-config.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> |
该引擎接收到请求动作后,将该动作分发至系统管理逻辑处理单元就是/WEB-INF/main-config.xml文件
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/loginInit.do">loginController</prop> <prop key="/loginSubmit.do">loginController</prop> </props> </property> </bean> |
main-config.xml文件通过urlMapping中定义的请求动作与控制器的映射
<prop key="/loginInit.do">loginController</prop>
将动作交由loginController所定义的控制器处理
<bean id="loginController" class="com.manage.LoginController"> <property name="bean"><ref bean="bean"/></property> <property name="sqlMap"><ref bean="sqlMap"/></property> <property name="formView"><value>login</value></property> <property name="successView"><value>main</value></property> <property name="mainField"> <list> <value>usercode</value> <value>password</value> </list> </property> </bean> |
该控制器引用了applicationContext.xml文件中加载的bean和sqlMap实例
<property name="bean"><ref bean="bean"/></property>
<property name="sqlMap"><ref bean="sqlMap"/></property>
以及对控制器处理请求后返回的视图属性的定义
<property name="formView"><value>login</value></property>
<property name="successView"><value>main</value></property>
com.manage.LoginController控制器主要实现了
public ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception 方法,该方法主要是对请求动作进行处理并返回一个ModelAndView对象,ModelAndView类包含了逻辑单元返回的结果数据集和表现层信息
public ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
log.info(request.getMethod()); Map model = new HashMap(); Map userForm =null; Map userInfo = null;
if(isGet(request)){ userForm = new HashMap(); userForm.put("usercode","A1118"); userForm.put("password","123"); model.put("userForm",userForm); return new ModelAndView(formView,model); } else{ userForm = (Map)bean.fillMap(mainField, request); try{ sqlMap.startTransaction(); userInfo = (Map)sqlMap.queryForObject("user.selectUser", userForm.get("usercode")); sqlMap.commitTransaction(); } finally{ sqlMap.endTransaction(); } if(userInfo == null){ model.put("message", "没有找到该用户"); model.put("userForm", userForm); returnView = formView; } else{ model.put("message", "登录成功"); model.put("userInfo", userInfo); returnView = successView; printMap(userInfo); request.getSession().setAttribute("userInfo", userInfo); } return new ModelAndView(returnView, model); } } |
这里我是用一个控制器对登录的初始化动作和登录提交动作进行控制,通过
if(isGet(request))来区分,初始化动作中将用户信息封装在model中并通过
return new ModelAndView(formView,model);
formView是请求动作返回的视图,在配置文件中已经定义了
<property name="formView"><value>login</value></property>
model是返回的结果数据集
将返回的视图和数据集交由urlMapping,urlMapping会根据applicationContext.xml中定义的
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass"><value>org.springframework.web.servlet.view.JstlView</value></property> <property name="prefix"><value>/WEB-INF/view/</value></property> <property name="suffix"><value>.jsp</value></property> </bean>
|
viewResolver在返回的视图的字符串加上前缀/WEB-INF/view/和后缀.jsp,即
/WEB-INF/view/login.jsp,
然后通过main的调度引擎返回到login页面
<%@ page contentType="text/html; charset=GBK" %> <%@ include file="/WEB-INF/view/inc/head.jsp" %> <html> <head> <title> login </title> <%@ include file="/WEB-INF/view/inc/css-js.inc" %> </head> <body bgcolor="#ffffff"> <spring:message code="title"/> <spring:message code="fff"/>
<form action="/loginSubmit.do" method="POST"> <table width="100%" height="100%"> <tr> <td align="center" valign="middle"> <c:if test="${message!=null}"> <h4><c:out value="${message}" /></h4><br> </c:if> 用户编号:<input type="text" name="usercode" value="<c:out value="${userForm.usercode}"/>"/> <br/> 用户密码:<input type="text" name="password" value="<c:out value="${userForm.password}"/>"/> <br/> <input type="submit" value="ok"/> </td> </tr> </table> </form> </body> </html> |
Login页面上使用了jstl的标签进行输出。这样一个登录初始化的过程就完成,
登录提交的原理和登录初始化的运行原理一样,
在登录提交过程中我也是使用的com.manage.LoginController控制器,在提交过程中我通过
userForm = (Map)bean.fillMap(mainField, request);方式将页面提交过来的表单数据封装在
userForm中的(订货单模块中都是用bean.fillMap和bean.fillMaps来封装请求参数的),,这里的mainField是一个字符串数组,由LoginController的父类SimpleController中定义,bean也是在SimpleController定义的
mainField的作用是设置表单提交过来的字段,通过在配置文件中定义,这样可以避免硬编码,
<property name="mainField"> <list> <value>usercode</value> <value>password</value> </list> </property> |
Bean的作用是将请求的表单中的数据以key和value 形式封装在Map中
在提交过程中我使用了ibatis中的核心组件sqlMap,也是在配置文件中定义的
<property name="sqlMap"><ref bean="sqlMap"/></property>
SqlMap的调用方法如下
try{
sqlMap.startTransaction();开启事务
userInfo = (Map)sqlMap.queryForObject("user.selectUser", userForm.get("usercode"));
sqlMap.commitTransaction();提交事务
}
finally{
sqlMap.endTransaction();结束事务
}
(Map)sqlMap.queryForObject("user.selectUser", userForm.get("usercode"));方法用于查询用户的信息,"
user.selectUser"是对应于user.xml映射文件中的selectUser对sql语句的映射,userForm.get("usercode")是输入的参数
<select id="selectUser" parameterClass="java.lang.String" resultClass="java.util.HashMap"> <![CDATA[ select * from v_BsUserRole where userCode = #userCode# ]]> </select> |
Id就是调用sql的引用名,
parameterClass是输入的参数
resultClass是返回的结果集封装的类
sqlMap.queryForObject会根据输入的sql的引用名来完成查询和数据封装工作,
如果找到记录,则封装在resultClass定义的对象中返回,没有找到则返回null
执行完毕后,LoginController会返回main页面或login页面。
整个程序中运行的流程大致相同,下面将对ibatis的使用进行说明
示例中我使用了以下几种查询和数据库的操作
? 查询订货单记录
查询单条记录在订货单修改时用到,类为
com.indent.IndentModController
订货单是主从表关系,因此需要配置主表查询语句和从表查询语句
sql的映射文件为indent.xml文件
<select id="getIndent" parameterClass="java.lang.String" resultClass="java.util.HashMap"> <![CDATA[ select sellID, sellIDShow, dealerCode, dealerName, orderCode, orderName, orderDate, sumSellNum, sumFeeSell, source, sourceExplain, status, statusExplain,remark from V_OS_Sell where sellID = #sellID# ]]> </select> <select id="getIndentList" parameterClass="java.lang.String" resultClass="java.util.HashMap"> <![CDATA[ select partCode, partName, unit, priceSell, numStorage, orderNum, orderSum from V_OS_SellList where sellID = #sellID# ]]> </select> |
Id:程序中对sql的引用名
parameterClass:输入参数,
resultClass:封装每条记录的类
对于查询一条记录时ibatis直接返回resultClass中定义的封装数据的对象
对于查询多条记录,ibatis会将每条记录封装在resultClass定义的对象实例中然后将所有这所对象封装在List中返回
Map indent = null; List indentList = null; try{ sqlMap.startTransaction(); indent=(Map)sqlMap.queryForObject("indent.getIndent",sellID);订货单主表记录 indentList = sqlMap.queryForList("indent.getIndentList",sellID);订货单从表记录 sqlMap.commitTransaction(); } finally{ sqlMap.endTransaction(); } |
? 动态条件查询
动态条件查询是指通过查询页面提交的动态条件来组合不同的sql语句
我们以前是通过
String sql ="select * from table where bh='dd'"
If(request. getParameter("par")!=null&& request. getParameter("par"). length()>0){
sql += " and field = '"+ request. getParameter("par")+"'";
}
…….
这种方式来组合的
考虑到这个问题,ibatis引入了动态映射机制
在订货单查询就用到了这种动态条件查询,对应的类是com.indent.IndentQueryController
首先我通过
indentForm = (Map)bean.fillMap(mainField, request);方法将查询条件封装在Map中
然后将这个查询条件的对象交给sqlMap查询
partCount = ((Integer) sqlMap.queryForObject("indent.getIndentQueryCount", indentForm)).intValue();获得了查询的记录数
indentList=sqlMap.queryForList("indent.getIndentQuery", indentForm, skipResult, PAGE_SIZE);获得了分页的记录集
sql映射是
<select id="getIndentQueryCount" parameterClass="java.util.Map" resultClass="java.lang.Integer"> <![CDATA[ select count(sellID) from os_sell where (depotCode = #depotCode#) and (oldSellID is null) and (status='1') ]]> <dynamic prepend="AND"> <isNotEmpty prepend="AND" property="sellID"> <![CDATA[(sellID like '%'+#sellID#+'%')]]> </isNotEmpty> <isNotEmpty prepend="AND" property="dealerName"> <![CDATA[(dealerName like '%'+#dealerName#+'%')]]> </isNotEmpty> <isNotEmpty prepend="AND" property="orderCode"> <![CDATA[(orderCode = #orderCode#)]]> </isNotEmpty> <isNotEmpty prepend="AND" property="orderDate1"> <![CDATA[(orderDate >= #orderDate1#)]]> </isNotEmpty> <isNotEmpty prepend="AND" property="orderDate2"> <![CDATA[(orderDate <= #orderDate2#)]]> </isNotEmpty> </dynamic> </select>
<select id="getIndentQuery" parameterClass="java.util.Map" resultClass="java.util.HashMap"> <![CDATA[ select sellID, sellIDShow, dealerName, sumSellNum, sumFeeSell, orderName, orderDate, sourceExplain from V_OS_Sell where (depotCode = #depotCode#) and (oldSellID is null) and (status='1') ]]> <dynamic prepend="AND"> <isNotEmpty prepend="AND" property="sellID"> <![CDATA[(sellID like '%'+#sellID#+'%')]]> </isNotEmpty> <isNotEmpty prepend="AND" property="dealerName"> <![CDATA[(dealerName like '%'+#dealerName#+'%')]]> </isNotEmpty> <isNotEmpty prepend="AND" property="orderCode"> <![CDATA[(orderCode = #orderCode#)]]> </isNotEmpty> <isNotEmpty prepend="AND" property="orderDate1"> <![CDATA[(orderDate >= #orderDate1#)]]> </isNotEmpty> <isNotEmpty prepend="AND" property="orderDate2"> <![CDATA[(orderDate <= #orderDate2#)]]> </isNotEmpty> </dynamic> <![CDATA[ order by orderDate desc, sellID desc ]]> </select> |
对于动态映射的配置,大家可以看<ibatis开发指南>的31-34页里面讲得很清楚
? 操作语句
操作语句包括订货单的插,改,删
这里只说一下订货单的插入过程,类是com.indent.IndentAddSaveController
首先IndentAddSaveController在获得提交保存的请求后,将订货单主表信息封装在map,从表信息封装在list中
Map indent = (Map)bean.fillMap(mainField,request);
List indentList = bean.fillMaps(childField,request);
然后通过事务管理,插入订货单主表信息,循环插入订货单子表信息
try{ sqlMap.startTransaction(); sqlMap.insert("indent.insertIndent",indent); for (int i = 0; i < indentList.size(); i++) { indentPart = (Map)indentList.get(i) ; indentPart.put("sellID",sellID); sqlMap.insert("indent.insertIndentList",indentPart); } sqlMap.commitTransaction(); } finally{ sqlMap.endTransaction(); } |
对应的sql配置是
<insert id="insertIndent" parameterClass="java.util.Map"> <![CDATA[ insert into OS_Sell (sellID,dealerCode,dealerName,depotCode,orderCode,orderDate, sumSellNum,sumFeeSell,source,status,remark,isBack) values(#sellID#,#dealerCode#,#dealerName#,#depotCode#,#orderCode#,#orderDate#, #sumSellNum#,#sumFeeSell#,#source#,'1',#remark#,'2'); ]]> </insert>
<insert id="insertIndentList" parameterClass="java.util.Map"> <![CDATA[ insert into OS_SellList (sellID, partCode, partName, unit, priceSell, orderNum) values (#sellID#, #partCode#, #partName#, #unit#, #priceSell#, #orderNum#) ]]> </insert> |
? 调用存储过程
存储过程的调用在订货单新建过程中用到,订货单新建时首先要获得一个唯一的ID号
对应的类是com.indent. IndentAddController
首先我将存储过程需要用到的参数封装在map中,提交给sqlMap执行存储过程
Map parMap = null; try { sqlMap.startTransaction(); parMap = new HashMap(); parMap.put("type","X"); parMap.put("depot","A1118"); parMap.put("code",null); sqlMap.update("common.getCode",parMap); sqlMap.commitTransaction(); } finally { sqlMap.endTransaction(); } String sellID=(String)parMap.get("code"); |
SqlMap会根据common.getCode所定的parameterMap
<parameterMap id="getCodeParameters" class="java.util.Map" > <parameter property="type" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN" /> <parameter property="depot" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/> <parameter property="code" jdbcType="VARCHAR" javaType="java.lang.String" mode="OUT" nullValue=""/> </parameterMap>
<procedure id="getCode" parameterMap="getCodeParameters"> <![CDATA[ {call ProcGetMaxId(?,?,?)} ]]> </procedure> |
的输入输出参数来定义存储过程中的参数
这里我将code这个字段定义为OUT型,那么存储过程执行后会将返回的唯一的ID号存储在code中,在程序中就通过
String sellID=(String)parMap.get("code");可以得到了。
? 注意一点
sqlMap的执行默认情况下是自动提交的,在没有用
try {
sqlMap.startTransaction();
………..
sqlMap.commitTransaction();
}
finally {
sqlMap.endTransaction();
}
进行事务管理时
每执行一个更新,查询,等数据访问方法时都会打开,和关闭一次连接,
因此,在一个动作中多次调用sqlMap的数据访问方法时都应该用事务来管理,不管是查询,还是更新。
《spring开发指南》中需要重点看的章节
? Spring Bean封装机制 19-28页 要会配置Bean
? Spring 高级特性 29-64页 要明白其中的登录例子的流程
《ibatis开发指南》中需要重点看的章节
? ibatis配置 11-16页
? SqlMapClient基本操作示例 16-17页 例1-例6
? OR 映射 19-25页
? 动态映射 31-34页
? 事务管理-基于JDBC的事务管理机制 35-36页
附:
表结构
BS订货单主表 CREATE TABLE [dbo].[OS_Sell] ( [SellID] [nvarchar] (17) COLLATE Chinese_PRC_CI_AS NOT NULL , [DealerCode] [nvarchar] (6) COLLATE Chinese_PRC_CI_AS NULL , [DealerName] [nvarchar] (60) COLLATE Chinese_PRC_CI_AS NULL , [DepotCode] [nvarchar] (6) COLLATE Chinese_PRC_CI_AS NOT NULL , [StockID] [nvarchar] (17) COLLATE Chinese_PRC_CI_AS NULL , [OrderCode] [nvarchar] (8) COLLATE Chinese_PRC_CI_AS NULL , [OrderDate] [datetime] NULL , [SumSellNum] [numeric](9, 1) NULL , [SumFeeSell] [numeric](10, 2) NULL , [ChangeCode] [nvarchar] (8) COLLATE Chinese_PRC_CI_AS NULL , [ChangeDate] [datetime] NULL , [AuditCode] [nvarchar] (8) COLLATE Chinese_PRC_CI_AS NULL , [AuditDate] [datetime] NULL , [OutCode] [nvarchar] (8) COLLATE Chinese_PRC_CI_AS NULL , [OutDate] [datetime] NULL , [Source] [char] (1) COLLATE Chinese_PRC_CI_AS NOT NULL , [Status] [char] (1) COLLATE Chinese_PRC_CI_AS NOT NULL , [Remark] [nvarchar] (100) COLLATE Chinese_PRC_CI_AS NULL , [IsBack] [char] (1) COLLATE Chinese_PRC_CI_AS NOT NULL , [OldSellID] [nvarchar] (17) COLLATE Chinese_PRC_CI_AS NULL , [BackStatus] [nvarchar] (1) COLLATE Chinese_PRC_CI_AS NULL , [InvoiceCode] [nvarchar] (8) COLLATE Chinese_PRC_CI_AS NULL , [InvoiceNO] [nvarchar] (10) COLLATE Chinese_PRC_CI_AS NULL , [InvoiceDate] [datetime] NULL ) ON [PRIMARY] |
BS订货单从表 CREATE TABLE [dbo].[OS_SellList] ( [SellID] [nvarchar] (17) COLLATE Chinese_PRC_CI_AS NOT NULL , [PartCode] [nvarchar] (30) COLLATE Chinese_PRC_CI_AS NOT NULL , [PartName] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL , [Unit] [nvarchar] (4) COLLATE Chinese_PRC_CI_AS NULL , [PriceSell] [numeric](8, 2) NULL , [OrderNum] [numeric](9, 1) NULL , [OutNum] [numeric](9, 1) NULL , [BackNum] [numeric](9, 1) NULL ) ON [PRIMARY] |
总部库存表 CREATE TABLE [dbo].[O_Storage] ( [DepotCode] [nvarchar] (6) COLLATE Chinese_PRC_CI_AS NOT NULL , [PartCode] [nvarchar] (30) COLLATE Chinese_PRC_CI_AS NOT NULL , [PartName] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL , [Unit] [nvarchar] (4) COLLATE Chinese_PRC_CI_AS NULL , [ProviderCode] [nvarchar] (4) COLLATE Chinese_PRC_CI_AS NULL , [NumStorage] [numeric](9, 1) NULL , [NumFreeze] [numeric](9, 1) NULL , [PriceCost] [numeric](8, 2) NULL , [PricePact] [numeric](8, 2) NULL , [PriceMove] [numeric](8, 2) NULL , [PriceStatus] [char] (1) COLLATE Chinese_PRC_CI_AS NOT NULL , [StorageCode] [nvarchar] (14) COLLATE Chinese_PRC_CI_AS NULL ) ON [PRIMARY] |
视图
--BS中的用户角色视图 --姜敏 CREATE view v_BsUserRole as select a.dealerCode,--经销商编号 a.areaCode,--区域编号 a.dealerName,--经销商名称 a.depotName,--仓库名称 a.kind,--等级分类 a.status as dealerStatus,--经销商状态 a.upDealerCode,--上级经销商代码 b.userCode,--用户代码 b.userName,--用户姓名 LOWER(b.password) as password ,--用户密码 b.lindType,--联系方式 b.status as userStatus,--用户状态 b.isAdmin,--是否管理员 c.roleCode,--角色编号 c.roleName--角色名称
from p_dealer a inner join p_user b on a.dealercode=b.depotcode left outer join (select a.roleCode, a.roleName, b.userCode from r_bsRole a inner join r_bsRoleUser b on a.RoleCode = b.RoleCode) c on b.userCode=c.userCode |
订货单主表视图 CREATE VIEW dbo.V_OS_Sell AS SELECT a.sellID, right(a.sellID,10) as sellIDShow, a.dealerCode, a.dealerName, f.areaCode, f.areaName, a.depotCode, h.dealerName AS depotName, a.stockID, a.orderCode, b.userName AS orderName, CONVERT(char(10), a.orderDate, 120) AS orderDate, cast(a.sumSellNum AS int) AS sumSellNum, a.sumFeeSell, a.changeCode, g.userName AS changeName, CONVERT(char(10), a.changeDate, 120) AS changeDate, a.auditCode, c.userName AS auditName, CONVERT(char(10), a.auditDate, 120) AS auditDate, a.outCode, d .userName AS outName, CONVERT(char(10), a.outDate, 120) AS outDate, a.source, (CASE a.source WHEN '1' THEN '转单' WHEN '2' THEN '自制' END) AS sourceExplain, a.status, (CASE a.status WHEN '1' THEN '已订货' WHEN '2' THEN '已转单' WHEN '3' THEN '已审核' WHEN '4' THEN '已出库' WHEN '5' THEN '已发运' WHEN ' 6 ' THEN '已确认' END) AS statusExplain, a.remark, a.isBack, (CASE a.isBack WHEN '1' THEN '是' WHEN '2' THEN '否' END) AS isBackExplain, a.oldSellID, a.backStatus, (CASE a.backStatus WHEN '1' THEN '未审核' WHEN '2' THEN '已审核' WHEN '3' THEN '已退货' END) AS backStatusExplain FROM OS_Sell a INNER JOIN P_User b ON a.orderCode = b.userCode INNER JOIN P_Dealer e ON a.dealerCode = e.dealerCode INNER JOIN P_Dealer h ON a.depotCode = h.dealerCode LEFT OUTER JOIN P_Area f ON e.AreaCode = f.AreaCode LEFT OUTER JOIN P_User c ON a.auditCode = c.userCode LEFT OUTER JOIN P_User d ON a.outCode = d .userCode LEFT OUTER JOIN P_User g ON a.changeCode = g.userCode
|
订货单从表视图 /* 平台销售单子表 姜敏 */ CREATE view V_OS_SellList as
select a.sellID, --销售单ID a.partCode, --零件号 a.partName, --零件名称 a.unit, --计量单位 a.priceSell, --销售价(合同成本价) isnull((select top 1 pricePact from o_storage where depotCode='000001' and partCode = a.partCode),0) as factPrice,--当前的总部的销售价 cast(isnull((select top 1 numStorage from o_storage where depotCode = '000001' and partcode = a.partcode),0) as int) as numStorage, --当前库存数量 cast(a.orderNum as int) as orderNum, --订货数量 a.priceSell*orderNum as orderSum, --订货金额 cast(a.outNum as int) as outNum, --出库数量 a.priceSell*outNum as outSum, --出库金额 cast(a.backNum as int) as backNum, --累计退票数量 a.priceSell*backNum as backSum, --累计退票金额 cast((a.orderNum+a.backNum) as int) as canBackNum, --可退数量 (a.orderNum+a.backNum)*a.priceSell as canBackSum--可退金额
from OS_SellList a inner join OS_Sell b on a.sellID = b.sellID
|
存储过程
--取单据号的存储过程-- CREATE PROCEDURE ProcGetMaxId @LX char(1),@CK nvarchar(6),@Code nvarchar(17) output AS Declare @i bigint,@No Varchar(11) begin tran Select @i=count(*) from P_MaxId where (Code = @LX) and (DepotCode=@CK) if @i>0 begin set @i=0 Select @i=IDNO FROM P_MaxId WHERE (CONVERT(Varchar, CurrDate, 1) = CONVERT(Varchar, GETDATE(), 1)) AND (Code = @LX) and (DepotCode=@CK) if @i=0 begin Set @No=Convert(Varchar,Getdate(),112)+'001' Update P_MaxId Set CurrDate=GetDate(),IDNO=Convert(bigint,@No) where (Code = @LX) and (DepotCode=@CK) end else begin Update P_MaxId Set CurrDate=GetDate(),IDNO=IDNO+1 where (Code = @LX) and (DepotCode=@CK) end Select @No=Convert(varchar,IDNO) from P_MaxId where (Code = @LX) and (DepotCode=@CK) end else begin Set @No=Convert(Varchar,Getdate(),112)+'001' Insert P_MaxId(Code,DepotCode,CurrDate,IDNO) Values( @LX,@CK,GetDate(),Convert(bigint,@No) ) end commit tran set @Code= @CK+'_'+@LX+subString(@No,3,9) --return 1
GO |