插入ts以及判断列是否存在(支持多数据库)

本文介绍了一种在不同类型的数据库中(如SQL Server、Oracle、PostgreSQL等)判断指定表是否存在特定字段的方法,并提供了添加时间戳字段(ts)及默认值为0的数值字段(dr)的具体实现。
 1:增加ts.dr字段,先判断ts.dr字段是否存在,其中ts字段插入的是日期,默认值为当前插入的时间,dr字段是数值型,默认值为0

* 增加ts/dr字段 * * @param tableList */ private void addTSAndDRColumn(List<String> tableList) { // 先判断是否有ts,dr列 String dsname = getDsName(); boolean addTS = false; boolean addDR = false; List<String> sqlList = new ArrayList<String>(); for (int i = 0; i < tableList.size(); i++) { String addSql = null; String tableName = tableList.get(i); addTS = !isColumnExist(dsname, tableName, "ts"); addDR = !isColumnExist(dsname, tableName, "dr"); if (addTS) { if (addDR) { addSql = addTSAndDR(tableName); } else { addSql = addTS(tableName); } } else { if (addDR) { addSql = addDR(tableName); } } if (!StringUtils.isEmpty(addSql)) { sqlList.add(addSql); } } String[] sqls = sqlList.toArray(new String[0]); if (!ArrayUtils.isEmpty(sqls)) { SqlExecAction_Client.execBatch(dsname, sqls);// 批量处理 } } /** * 判断列是否存在。思路:针对sqlserver/oracle/postgrel做了特殊处理,其他类型的数据库,则按照字段执行查询,如果出错,则说明字段不存在 *
* @param dsname * 数据源 * @param tableName * 表名 * @param column * 列名 * @return
*/ private boolean isColumnExist(String dsname, String tableName, String column) { boolean isExist = true; DbType dbType = SmartUtilities.getDbType(dsname); if (dbType == DbType.SQLSERVER || dbType == DbType.ORACLE || dbType == DbType.POSTGRESQL) { return isColumnExist(dsname, tableName, column, dbType); } else { try { String sql = "select count(" + column + ") from " + tableName; SqlExecAction_Client.execQuery(dsname, sql, new ResultSetProcessor() { private static final long serialVersionUID = -3528176693847689283L; @Override public Object handleResultSet(ResultSet rs) throws SQLException { while (rs.next()) { return rs.getInt(1); } return 0; } }); } catch (Exception e) {// 如果有异常,则说明字段不存在 AppDebug.error(e); isExist = false; } } return isExist; } private boolean isColumnExist(String dsname, String tableName, String column, DbType dbType) { String sql = null; if (dbType == DbType.SQLSERVER) { sql = "select count(*) from syscolumns where id=object_id('" + tableName.toLowerCase() + "') and name='" + column + "'"; } else if (dbType == DbType.ORACLE) { sql = "select count(*) from cols where table_name=upper('" + tableName + "') and column_name=upper('" + column + "')"; } else if (dbType == DbType.POSTGRESQL) { sql = "select count(*) from pg_attribute where attname='" + column + "' and attrelid=(select oid from pg_class where relname='" + tableName.toLowerCase() + "')"; } Integer count = (Integer) SqlExecAction_Client.execQuery(dsname, sql, new ResultSetProcessor() { private static final long serialVersionUID = -3528176693847689283L; @Override public Object handleResultSet(ResultSet rs) throws SQLException { while (rs.next()) { return rs.getInt(1); } return 0; } }); int icount = count.intValue(); return (icount != 0); } /** * @param tableName * @return */ private String addTSAndDR(String tableName) { String sql = "alter table " + tableName + " add (ts CHAR(19),dr numeric(10,0) DEFAULT 0)"; String dsName = FileStorageConfigFactory.getBaseConfig().getDsName(); DbType dbType = SmartUtilities.getDbType(dsName); if (dbType == DbType.SQLSERVER) { sql = "alter table " + tableName + " add ts NCHAR(19) COLLATE Chinese_PRC_CI_AS DEFAULT CONVERT(nchar(19),GETDATE(),20),dr SMALLINT DEFAULT 0"; } else if (dbType == DbType.ORACLE) { sql = "alter table " + tableName + " add (ts CHAR(19) DEFAULT to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),dr numeric(10,0) DEFAULT 0)"; } else if (dbType == DbType.DB2) { sql = "alter table " + tableName + " add COLUMN ts CHAR(19) DEFAULT char(current timestamp,'yyyy-mm-dd hh24:mi:ss')" + " add COLUMN dr SMALLINT DEFAULT 0)"; } else if (dbType == DbType.POSTGRESQL) { sql = "alter table " + tableName + " add ts CHAR(19) DEFAULT to_char(current_timestamp,'yyyy-mm-dd hh24:mi:ss'),add dr numeric(10,0) DEFAULT 0"; } return sql; } private String addTS(String tableName) { String sql = "alter table " + tableName + " add ts CHAR(19)"; String dsName = FileStorageConfigFactory.getBaseConfig().getDsName(); DbType dbType = SmartUtilities.getDbType(dsName); if (dbType == DbType.SQLSERVER) { sql = "alter table " + tableName + " add ts NCHAR(19) COLLATE Chinese_PRC_CI_AS DEFAULT CONVERT(nchar(19),GETDATE(),20)"; } else if (dbType == DbType.ORACLE) { sql = "alter table " + tableName + " add ts CHAR(19) DEFAULT to_char(sysdate,'yyyy-mm-dd hh24:mi:ss')"; } else if (dbType == DbType.DB2) { sql = "alter table " + tableName + " add COLUMN ts CHAR(19) DEFAULT char(current timestamp,'yyyy-mm-dd hh24:mi:ss')"; } else if (dbType == DbType.POSTGRESQL) { sql = "alter table " + tableName + " add ts CHAR(19) DEFAULT to_char(current_timestamp,'yyyy-mm-dd hh24:mi:ss')"; } return sql; } private String addDR(String tableName) { String sql = "alter table " + tableName + " add dr numeric(10,0) DEFAULT 0"; String dsName = FileStorageConfigFactory.getBaseConfig().getDsName(); DbType dbType = SmartUtilities.getDbType(dsName); if (dbType == DbType.SQLSERVER) { sql = "alter table " + tableName + " add dr SMALLINT DEFAULT 0"; } else if (dbType == DbType.DB2) { sql = "alter table " + tableName + " add COLUMN dr SMALLINT DEFAULT 0)"; } return sql; }

 

转载于:https://www.cnblogs.com/chenfei0801/p/3477617.html

### 数据库设计 (SQL Server) #### 1. 核心表结构 ```sql -- 票价类型表 CREATE TABLE TicketType ( TypeID INT PRIMARY KEY IDENTITY(1,1), TypeName NVARCHAR(20) NOT NULL CHECK (TypeName IN ('老年', '小孩', '成人', '团体')), BasePrice DECIMAL(10,2) NOT NULL, DiscountRate DECIMAL(5,2) DEFAULT 1.0, Description NVARCHAR(255) ); -- 营业员表 CREATE TABLE Salesperson ( SalespersonID INT PRIMARY KEY IDENTITY(1,1), EmployeeID NVARCHAR(20) UNIQUE NOT NULL, Name NVARCHAR(50) NOT NULL, Password NVARCHAR(100) NOT NULL, Role NVARCHAR(20) DEFAULT 'staff' CHECK (Role IN ('admin', 'staff')), IsActive BIT DEFAULT 1 ); -- 门票销售表 CREATE TABLE TicketSale ( SaleID INT PRIMARY KEY IDENTITY(1,1), TypeID INT NOT NULL REFERENCES TicketType(TypeID), SalespersonID INT NOT NULL REFERENCES Salesperson(SalespersonID), Quantity INT NOT NULL CHECK (Quantity > 0), UnitPrice DECIMAL(10,2) NOT NULL, -- 销售时单价(可能含折扣) TotalAmount DECIMAL(10,2) NOT NULL, SaleTime DATETIME DEFAULT GETDATE(), IsRefund BIT DEFAULT 0 ); -- 退票记录表 CREATE TABLE RefundRecord ( RefundID INT PRIMARY KEY IDENTITY(1,1), SaleID INT NOT NULL REFERENCES TicketSale(SaleID), RefundQuantity INT NOT NULL CHECK (RefundQuantity > 0), RefundAmount DECIMAL(10,2) NOT NULL, RefundTime DATETIME DEFAULT GETDATE(), Reason NVARCHAR(255) ); ``` #### 2. 表间关系图 ```mermaid erDiagram TicketType ||--o{ TicketSale : "1:N" Salesperson ||--o{ TicketSale : "1:N" TicketSale ||--o{ RefundRecord : "1:N" TicketType { int TypeID PK nvarchar(20) TypeName decimal(10,2) BasePrice decimal(5,2) DiscountRate nvarchar(255) Description } Salesperson { int SalespersonID PK nvarchar(20) EmployeeID nvarchar(50) Name nvarchar(100) Password nvarchar(20) Role bit IsActive } TicketSale { int SaleID PK int TypeID FK int SalespersonID FK int Quantity decimal(10,2) UnitPrice decimal(10,2) TotalAmount datetime SaleTime bit IsRefund } RefundRecord { int RefundID PK int SaleID FK int RefundQuantity decimal(10,2) RefundAmount datetime RefundTime nvarchar(255) Reason } ``` #### 3. 储过程实现 ##### a. 统计指定日期的门票销售情况 ```sql CREATE PROCEDURE sp_DailySalesSummary @TargetDate DATE AS BEGIN SELECT TT.TypeName AS 票种类型, SUM(TS.Quantity) AS 总票数, SUM(TS.TotalAmount) AS 总收入 FROM TicketSale TS JOIN TicketType TT ON TS.TypeID = TT.TypeID WHERE CAST(TS.SaleTime AS DATE) = @TargetDate AND TS.IsRefund = 0 GROUP BY TT.TypeName ORDER BY 总收入 DESC; END; GO ``` ##### b. 统计指定月份的门票销售情况 ```sql CREATE PROCEDURE sp_MonthlySalesSummary @Year INT, @Month INT AS BEGIN SELECT TT.TypeName AS 票种类型, SUM(TS.Quantity) AS 总票数, SUM(TS.TotalAmount) AS 总收入 FROM TicketSale TS JOIN TicketType TT ON TS.TypeID = TT.TypeID WHERE YEAR(TS.SaleTime) = @Year AND MONTH(TS.SaleTime) = @Month AND TS.IsRefund = 0 GROUP BY TT.TypeName ORDER BY 总收入 DESC; END; GO ``` ##### c. 统计指定日期各种价格的门票销售情况 ```sql CREATE PROCEDURE sp_DailySalesByPrice @TargetDate DATE AS BEGIN SELECT TS.UnitPrice AS 销售单价, COUNT(TS.SaleID) AS 销售笔数, SUM(TS.Quantity) AS 总票数, SUM(TS.TotalAmount) AS 总收入 FROM TicketSale TS WHERE CAST(TS.SaleTime AS DATE) = @TargetDate AND TS.IsRefund = 0 GROUP BY TS.UnitPrice ORDER BY TS.UnitPrice DESC; END; GO ``` ##### d. 统计指定营业员指定日期的收费情况 ```sql CREATE PROCEDURE sp_SalespersonDailySummary @SalespersonID INT, @TargetDate DATE AS BEGIN SELECT SP.Name AS 营业员姓名, COUNT(TS.SaleID) AS 交易笔数, SUM(TS.Quantity) AS 总票数, SUM(TS.TotalAmount) AS 总收入 FROM TicketSale TS JOIN Salesperson SP ON TS.SalespersonID = SP.SalespersonID WHERE SP.SalespersonID = @SalespersonID AND CAST(TS.SaleTime AS DATE) = @TargetDate AND TS.IsRefund = 0 GROUP BY SP.Name; -- 附加:详细交易表 SELECT TT.TypeName AS 票种类型, TS.Quantity AS 数量, TS.UnitPrice AS 单价, TS.TotalAmount AS 金额, FORMAT(TS.SaleTime, 'HH:mm:ss') AS 销售时间 FROM TicketSale TS JOIN TicketType TT ON TS.TypeID = TT.TypeID WHERE TS.SalespersonID = @SalespersonID AND CAST(TS.SaleTime AS DATE) = @TargetDate AND TS.IsRefund = 0 ORDER BY TS.SaleTime DESC; END; GO ``` #### 4. 数据完整性约束 1. **主键约束**: - 所有表都有自增主键(IDENTITY) 2. **外键约束**: ```sql -- TicketSale 引用 TicketType ALTER TABLE TicketSale ADD CONSTRAINT FK_TicketSale_TicketType FOREIGN KEY (TypeID) REFERENCES TicketType(TypeID); -- TicketSale 引用 Salesperson ALTER TABLE TicketSale ADD CONSTRAINT FK_TicketSale_Salesperson FOREIGN KEY (SalespersonID) REFERENCES Salesperson(SalespersonID); -- RefundRecord 引用 TicketSale ALTER TABLE RefundRecord ADD CONSTRAINT FK_RefundRecord_TicketSale FOREIGN KEY (SaleID) REFERENCES TicketSale(SaleID); ``` 3. **检查约束**: ```sql -- 票价类型限制 ALTER TABLE TicketType ADD CONSTRAINT CHK_TicketType_Name CHECK (TypeName IN ('老年', '小孩', '成人', '团体')); -- 角色限制 ALTER TABLE Salesperson ADD CONSTRAINT CHK_Salesperson_Role CHECK (Role IN ('admin', 'staff')); -- 数量必须为正数 ALTER TABLE TicketSale ADD CONSTRAINT CHK_Quantity_Positive CHECK (Quantity > 0); ALTER TABLE RefundRecord ADD CONSTRAINT CHK_RefundQuantity_Positive CHECK (RefundQuantity > 0); ``` 4. **默认值**: ```sql -- 默认折扣率 ALTER TABLE TicketType ADD CONSTRAINT DF_DiscountRate DEFAULT 1.0 FOR DiscountRate; -- 默认销售时间 ALTER TABLE TicketSale ADD CONSTRAINT DF_SaleTime DEFAULT GETDATE() FOR SaleTime; -- 默认退款时间 ALTER TABLE RefundRecord ADD CONSTRAINT DF_RefundTime DEFAULT GETDATE() FOR RefundTime; ``` #### 5. 索引优化 ```sql -- 加速日期范围查询 CREATE INDEX IX_TicketSale_SaleTime ON TicketSale(SaleTime); -- 加速按营业员查询 CREATE INDEX IX_TicketSale_Salesperson ON TicketSale(SalespersonID); -- 加速按票种查询 CREATE INDEX IX_TicketSale_Type ON TicketSale(TypeID); -- 唯一工号索引 CREATE UNIQUE INDEX UQ_Salesperson_EmployeeID ON Salesperson(EmployeeID); ``` #### 6. 触发器示例(退票时自动更新销售记录) ```sql CREATE TRIGGER trg_AfterRefund ON RefundRecord AFTER INSERT AS BEGIN SET NOCOUNT ON; UPDATE TS SET TS.IsRefund = CASE WHEN (TS.Quantity - i.RefundQuantity) <= 0 THEN 1 ELSE 0 END FROM TicketSale TS INNER JOIN inserted i ON TS.SaleID = i.SaleID; END; GO ``` ### 数据库设计说明 1. **票价管理表 (TicketType)**: - 储老年、小孩、成人、团体等票种 - 基础价格 + 折扣率 = 实际售价 - 支持票种描述信息 2. **营业员管理表 (Salesperson)**: - 唯一工号标识 - 角色区分管理员/普通营业员 - 激活状态控制账户可用性 3. **销售记录表 (TicketSale)**: - 记录每笔销售(票种、数量、单价、总额) - 包含销售时间和营业员信息 - 退票标志位(是否已退) 4. **退票记录表 (RefundRecord)**: - 关联原销售记录 - 记录退票数量、金额、时间和原因 - 支持部分退票 ### 储过程特点 1. **日期销售统计**: - 按天/月分组统计 - 按票种类型聚合数据 - 包含总票数和总收入 2. **价格分布分析**: - 按销售单价分组 - 统计同价格区间的销售情况 3. **营业员绩效统计**: - 汇总统计(总交易、总票数、总收入) - 详细交易表(每笔销售明细) ### 数据流示例 ```mermaid sequenceDiagram participant 前端 participant Servlet participant 数据库 前端->>Servlet: 提交销售请求 (票种ID, 数量) Servlet->>数据库: 获取票种价格 数据库-->>Servlet: 返回票价信息 Servlet->>Servlet: 计算总金额 Servlet->>数据库: 插入销售记录 数据库-->>Servlet: 返回销售ID Servlet-->>前端: 返回成功响应 前端->>Servlet: 请求退票 (销售ID, 数量) Servlet->>数据库: 检查原销售记录 数据库-->>Servlet: 返回原销售数据 Servlet->>Servlet: 计算可退金额 Servlet->>数据库: 插入退票记录 Servlet->>数据库: 更新原销售状态 数据库-->>Servlet: 操作成功 Servlet-->>前端: 返回退票结果 ``` 这个设计满足所有功能需求: 1. 完整的票价管理(四种票种类型) 2. 营业员账户管理系统 3. 售票和退票流程 4. 四个必需的储过程 5. 清晰的表间关系(主外键约束) 6. 数据完整性保障(检查约束) 系统支持每日/每月销售统计、价格分布分析、营业员绩效评估等核心业务场景,同时通过索引和储过程优化保证了查询性能。合成一下,给出完整代码
06-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值