ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

VB+SQL Server连锁超市进销存系统:从数据库设计到小票打印完整实现

VB+SQL Server连锁超市进销存系统:从数据库设计到小票打印完整实现 简介这份课程设计报告面向高校信息管理与信息系统、计算机相关专业学生围绕连锁超市进销存管理信息系统的分析与设计展开可作为课程设计、毕业设计选题的完整参考方案。报告从设计背景与可行性分析入手依次覆盖系统功能设计、总体用例图、业务流程活动图、功能操作序列图、状态图与类图并深入功能结构设计、数据库需求分析与结构设计、代码设计、输入输出设计及系统规格制订还给出体系结构图、物理配置方案与SQL Server 2000、VB 6.0、ADO编程模型等开发工具选型说明最后附典型界面与测试方案。资源包共1个doc文件约1.01MB结构完整、章节清晰便于按目录快速定位所需模块。目前已有66人学习适合需要系统梳理进销存系统分析设计流程、补齐UML建模与数据库设计环节的读者参考借鉴。1. 连锁超市进销存系统从课程设计到能跑通的桌面应用很多计算机专业的学生在做《信息系统分析与设计》课程设计时都会选连锁超市进销存管理信息系统这个题目。选它不是因为简单而是因为它把数据库设计、业务逻辑、界面交互三块内容全串起来了正好对应课程的核心考核点。但真正动手时你会发现难的不是写代码而是想清楚“进货、销售、库存”这三件事在数据库里怎么落、在界面上怎么串、在报表里怎么对得上。我见过太多人把 ER 图画得很漂亮一到写 SQL 就发现表结构根本撑不起业务查询。这篇内容就是按一线开发的路子把从建库、写核心业务逻辑到做报表的完整路径拆开讲用 SQL Server 做数据层、VB 做前端中间会给出可直接复用的建表语句、存储过程和 ADO 调用代码。适合正在做课程设计、需要交出一个能演示、能查数据、能打印小票的完整系统的同学也适合想用 VB SQL Server 快速搭一个进销存原型的小团队。2. 数据库设计三张核心表怎么撑起进销存2.1 商品、库存、流水的关系建模进销存系统的数据模型说复杂可以很复杂说简单也可以很简单。核心就三张表商品信息表、库存表、进出库流水表。商品信息表存的是静态数据——条码、名称、规格、进价、售价、供应商。库存表存的是动态数据——当前每个商品在每个门店的结存数量。流水表存的是每一次进货或销售的动作记录包括数量、单价、金额、时间、操作员。为什么要把库存和流水分开因为库存是“状态”流水是“事件”。状态可以随时被事件改变但事件必须被完整记录。很多同学一开始只建一张库存表每次进货就 update 数量结果月底想查“这个月进了多少货、卖了多少货”就傻眼了——数据已经被覆盖了。所以流水表是必须的而且流水表只增不改这是进销存系统的一条铁律。连锁超市还多一层门店。同一个商品在不同门店的库存是分开的所以库存表的主键应该是“商品编号 门店编号”。流水表也要带上门店编号否则跨店调拨和分店报表都做不了。下面是我一般会用的建表语句在 SQL Server 里直接跑就行-- 商品信息表 CREATE TABLE Goods ( GoodsID VARCHAR(20) PRIMARY KEY, -- 商品条码主键 GoodsName NVARCHAR(100) NOT NULL, -- 商品名称 Spec NVARCHAR(50), -- 规格 Unit NVARCHAR(10), -- 单位 PurchasePrice DECIMAL(10,2), -- 参考进价 SalePrice DECIMAL(10,2), -- 零售价 SupplierID VARCHAR(20), -- 供应商编号 IsActive BIT DEFAULT 1 -- 是否在售 ); -- 库存表按门店商品记录结存 CREATE TABLE Stock ( StoreID VARCHAR(10) NOT NULL, -- 门店编号 GoodsID VARCHAR(20) NOT NULL, -- 商品编号 Quantity INT DEFAULT 0, -- 当前库存数量 LastUpdated DATETIME DEFAULT GETDATE(), PRIMARY KEY (StoreID, GoodsID) ); -- 进出库流水表只增不改 CREATE TABLE StockFlow ( FlowID INT IDENTITY(1,1) PRIMARY KEY, StoreID VARCHAR(10) NOT NULL, GoodsID VARCHAR(20) NOT NULL, FlowType CHAR(1) NOT NULL, -- I进货 O销售 T调拨 Quantity INT NOT NULL, -- 变动数量进货为正销售为负 UnitPrice DECIMAL(10,2), -- 本次单价 TotalAmount DECIMAL(10,2), -- 本次金额 FlowTime DATETIME DEFAULT GETDATE(), Operator NVARCHAR(20) -- 操作员 );建完表之后记得给 StockFlow 的 FlowTime 和 GoodsID 建索引否则后面查月度报表会慢得让你怀疑人生。Stock 表的 StoreID GoodsID 已经是主键不用额外加索引。2.2 用触发器还是存储过程维护库存库存数量怎么更新有两种常见做法写触发器或者写存储过程。触发器的好处是“自动”——只要往流水表插一条记录库存表就自动变了前端代码不用管。坏处是“黑匣子”——出了问题不好排查而且批量导入数据时触发器逐条执行性能很差。我一般会推荐用存储过程把“插流水 改库存”放在一个事务里。这样逻辑清晰前端调用也简单出问题还能单独调试存储过程。下面这个存储过程处理进货入库CREATE PROCEDURE sp_StockIn StoreID VARCHAR(10), GoodsID VARCHAR(20), Qty INT, Price DECIMAL(10,2), Operator NVARCHAR(20) AS BEGIN SET NOCOUNT ON; BEGIN TRANSACTION; -- 1. 插入流水记录 INSERT INTO StockFlow (StoreID, GoodsID, FlowType, Quantity, UnitPrice, TotalAmount, Operator) VALUES (StoreID, GoodsID, I, Qty, Price, Qty * Price, Operator); -- 2. 更新库存如果记录不存在则插入 IF EXISTS (SELECT 1 FROM Stock WHERE StoreID StoreID AND GoodsID GoodsID) UPDATE Stock SET Quantity Quantity Qty, LastUpdated GETDATE() WHERE StoreID StoreID AND GoodsID GoodsID; ELSE INSERT INTO Stock (StoreID, GoodsID, Quantity) VALUES (StoreID, GoodsID, Qty); COMMIT TRANSACTION; END;这个存储过程的关键点用事务包住两个操作保证要么都成功要么都回滚。参数 Qty 传正数表示进货销售的时候传负数或者单独写一个 sp_StockOut 把数量取负。我习惯分开写因为销售还要校验库存够不够逻辑不一样。调用的时候在 VB 里用 ADO 的 Command 对象执行后面第 3 章会讲具体代码。3. VB ADO 把界面和数据库串起来3.1 连接 SQL Server 的两种方式与选型VB 连 SQL Server 常见两种方式ODBC DSN 和 OLEDB 连接字符串。DSN 的好处是配置一次到处能用坏处是换台机器就要重新配课程设计答辩时如果老师电脑没配 DSN 就直接翻车。所以我一般直接用 OLEDB 连接字符串写在代码里或者配置文件里走到哪都能跑。连接字符串长这样 模块级变量全局复用 Public Const CONN_STR As String _ ProviderSQLOLEDB;Data Source127.0.0.1;Initial CatalogSuperMarketDB; _ User IDsa;Password你的密码;Data Source 写 127.0.0.1 或者 localhost 都行如果 SQL Server 装在本机。Initial Catalog 是数据库名。User ID 用 sa 是最省事的但生产环境肯定不能这么干课程设计无所谓。注意 SQL Server 默认可能没开 sa 登录需要在 SSMS 里把 sa 启用并设置密码这个步骤在安装教程里都有不展开。连接和断开我封装成两个函数Public conn As ADODB.Connection Public Sub OpenDB() If conn Is Nothing Then Set conn New ADODB.Connection End If If conn.State adStateClosed Then conn.Open CONN_STR End If End Sub Public Sub CloseDB() If Not conn Is Nothing Then If conn.State adStateOpen Then conn.Close Set conn Nothing End If End Sub这里有个血泪经验conn 对象不要每次操作都 New 一个再关掉频繁开关连接在局域网里还行本机跑没问题但养成复用连接的习惯更好。OpenDB 里判断 State 再决定是否打开避免重复 Open 报错。3.2 用 ADO 执行存储过程并绑定到表格控件进货界面上一般有一个 MSHFlexGrid 或者 DataGrid 显示当前库存下面几个文本框输入进货数量点“确认入库”按钮就调存储过程。核心代码是这样Private Sub cmdStockIn_Click() On Error GoTo ErrHandler Dim cmd As New ADODB.Command Dim qty As Integer 校验输入 If Not IsNumeric(txtQty.Text) Then MsgBox 数量必须是数字 Exit Sub End If qty CInt(txtQty.Text) If qty 0 Then MsgBox 进货数量必须大于0 Exit Sub End If 调用存储过程 OpenDB Set cmd.ActiveConnection conn cmd.CommandType adCmdStoredProc cmd.CommandText sp_StockIn cmd.Parameters.Append cmd.CreateParameter(StoreID, adVarChar, adParamInput, 10, cboStore.Text) cmd.Parameters.Append cmd.CreateParameter(GoodsID, adVarChar, adParamInput, 20, txtGoodsID.Text) cmd.Parameters.Append cmd.CreateParameter(Qty, adInteger, adParamInput, , qty) cmd.Parameters.Append cmd.CreateParameter(Price, adCurrency, adParamInput, , CDbl(txtPrice.Text)) cmd.Parameters.Append cmd.CreateParameter(Operator, adVarWChar, adParamInput, 20, gUserName) cmd.Execute MsgBox 入库成功 Call RefreshStockGrid 刷新库存显示 Exit Sub ErrHandler: MsgBox 入库失败 Err.Description End Sub这段代码里几个关键参数说明adCmdStoredProc 告诉 ADO 这是存储过程而不是 SQL 文本。CreateParameter 的第三个参数 adParamInput 表示输入参数第四个参数是长度对字符串类型必须给第五个是值。adCurrency 对应 DECIMAL 类型adInteger 对应 INT。如果参数顺序和存储过程定义不一致会报“参数不足”或者“类型不匹配”这是新手最容易踩的坑。RefreshStockGrid 就是重新查一遍 Stock 表然后绑定到 GridPrivate Sub RefreshStockGrid() Dim rs As New ADODB.Recordset OpenDB rs.Open SELECT s.GoodsID, g.GoodsName, s.Quantity, g.SalePrice _ FROM Stock s JOIN Goods g ON s.GoodsID g.GoodsID _ WHERE s.StoreID cboStore.Text , conn, adOpenStatic, adLockReadOnly Set MSHFlexGrid1.DataSource rs Set rs Nothing End Sub注意 SQL 里字符串拼接用的是单引号cboStore.Text 如果带单引号会出问题但门店编号一般不会。更安全的做法是用参数化查询但课程设计里为了代码简洁直接拼也常见自己知道风险就行。4. 避坑与排查课程设计里最容易翻车的五个点4.1 连接失败SSL 证书链不受信任现象VB 程序一运行就报错提示“驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接”或者“证书链是由不受信任的颁发机构颁发的”。原因SQL Server 新版本默认强制加密连接而本机自签证书不被信任。解决在连接字符串里加Encryptno;TrustServerCertificateyes;或者去 SQL Server 配置管理器里把强制加密关掉。我一般直接在连接字符串里加改代码比改配置快。4.2 存储过程参数顺序错导致“参数不足”现象调用 sp_StockIn 时报“过程或函数 sp_StockIn 需要参数 Operator但未提供该参数”。原因CreateParameter 的顺序和存储过程定义的参数顺序不一致或者漏了某个参数。解决按存储过程定义的顺序逐个 Append一个都不能少。如果实在记不住顺序用命名参数的方式cmd.Parameters.Append cmd.CreateParameter(Qty, ...)这样即使顺序不同 ADO 也能匹配但 OLEDB 驱动对命名参数支持不完整最稳的还是按顺序写。4.3 库存出现负数现象销售出库后库存变成负数或者明明显示有货却提示库存不足。原因销售时没有校验当前库存或者并发操作时两个销售单同时扣减。解决在 sp_StockOut 里先SELECT Quantity FROM Stock WITH (UPDLOCK) WHERE ...锁住行判断够不够再扣减。课程设计里并发场景少但校验库存这一步不能省否则演示时卖一个库存为 0 的商品就尴尬了。4.4 报表查询超时现象查月度销售汇总时界面卡死等半天没反应。原因StockFlow 表数据量大FlowTime 字段没建索引全表扫描。解决CREATE INDEX IX_StockFlow_Time ON StockFlow(FlowTime);另外查询时尽量用WHERE FlowTime 2025-01-01 AND FlowTime 2025-02-01这种范围条件不要用YEAR(FlowTime) 2025后者会让索引失效。4.5 VB 里 ADO 记录集未关闭导致“连接忙”现象连续执行两次查询第二次报“连接正在执行命令”或者“对象打开时不允许操作”。原因上一次的 Recordset 没有 Close 就重新 Open 了。解决每次用完 Recordset 就rs.Close: Set rs Nothing或者用On Error Resume Next兜底。更规范的做法是写一个辅助函数传入 SQL 返回断开连接的 Recordset用完自动释放。5. 从课程设计到能演示三个让答辩加分的细节5.1 用视图简化复杂查询答辩时老师经常会问“你这个月度销售报表怎么查的”。如果你现场写一个五表 JOIN很容易写错。我一般会提前建好视图CREATE VIEW v_MonthlySales AS SELECT YEAR(f.FlowTime) AS SaleYear, MONTH(f.FlowTime) AS SaleMonth, f.StoreID, g.GoodsName, SUM(ABS(f.Quantity)) AS TotalQty, SUM(f.TotalAmount) AS TotalAmount FROM StockFlow f JOIN Goods g ON f.GoodsID g.GoodsID WHERE f.FlowType O GROUP BY YEAR(f.FlowTime), MONTH(f.FlowTime), f.StoreID, g.GoodsName;然后 VB 里直接SELECT * FROM v_MonthlySales WHERE SaleYear 2025简单明了。视图的另一个好处是权限控制——你可以只给用户视图的查询权限不给基表权限这在 SQL Server 2008R2 里就是“视图查询权限”那个选项。5.2 小票打印用 VB 的 Printer 对象课程设计里如果能现场打一张小票效果会好很多。VB 自带 Printer 对象不需要额外控件Private Sub PrintReceipt(goodsName As String, qty As Integer, price As Double) Printer.FontName 宋体 Printer.FontSize 10 Printer.Print 连锁超市销售小票 Printer.Print ------------------------ Printer.Print 商品 goodsName Printer.Print 数量 qty Printer.Print 单价 Format(price, 0.00) Printer.Print 金额 Format(qty * price, 0.00) Printer.Print 时间 Now Printer.Print ------------------------ Printer.Print 谢谢惠顾 Printer.EndDoc End SubPrinter.EndDoc 一执行默认打印机就出纸。如果没连打印机会弹一个保存打印文件的对话框也能演示。5.3 数据备份与还原的演示脚本答辩时老师可能让你演示“数据丢了怎么恢复”。提前准备一个备份脚本BACKUP DATABASE SuperMarketDB TO DISK D:\Backup\SuperMarketDB.bak WITH FORMAT;还原的时候RESTORE DATABASE SuperMarketDB FROM DISK D:\Backup\SuperMarketDB.bak WITH REPLACE;注意还原前要先让数据库脱机或者关掉所有连接否则会报“数据库正在使用”。在 VB 里演示的话先 CloseDB再执行还原再 OpenDB。这三个细节花不了多少时间但能让你的课程设计从“能跑”变成“像个真系统”。我当年做课设的时候就是靠一个小票打印和备份还原老师直接给了优秀。希望帮到你。本文还有配套的精品资源点击获取
返回列表