1. 首页 > DB2教程 > 正文

DB2教程FG102-DB2计费系统数据库实战

风哥教程参考DB2官方文档Billing Systems、Transaction Processing等内容,详细介绍计费系统设计、计费规则、账单生成等。更多视频教程www.fgedu.net.cn

目录大纲

Part01-计费系统概述

1.1 计费系统定义

计费系统是管理业务计费的核心系统:

  • 计费规则:定义计费标准和规则
  • 计费计算:根据规则计算费用
  • 账单生成:生成客户账单
  • 费用统计:统计和分析费用

1.2 计费类型

  • 按时长计费
  • 按流量计费
  • 按次数计费
  • 套餐计费
  • 阶梯计费

Part02-计费表设计

2.1 核心表设计

# 计费规则表
CREATE TABLE BILLING_RULE (
RULE_ID VARCHAR(32) NOT NULL,
RULE_NAME VARCHAR(100) NOT NULL,
RULE_TYPE VARCHAR(20) NOT NULL,
BILLING_UNIT VARCHAR(20) NOT NULL,
UNIT_PRICE DECIMAL(18, 4) NOT NULL,
MIN_CHARGE DECIMAL(18, 2) DEFAULT 0,
MAX_CHARGE DECIMAL(18, 2),
EFFECTIVE_DATE DATE NOT NULL,
EXPIRE_DATE DATE,
IS_ACTIVE CHAR(1) DEFAULT ‘Y’,
CONSTRAINT PK_BILLING_RULE PRIMARY KEY (RULE_ID)
);

CREATE INDEX IDX_RULE_TYPE ON BILLING_RULE(RULE_TYPE, EFFECTIVE_DATE);

# 阶梯计费规则表
CREATE TABLE TIERED_BILLING_RULE (
TIER_ID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
RULE_ID VARCHAR(32) NOT NULL,
MIN_VALUE DECIMAL(18, 2) NOT NULL,
MAX_VALUE DECIMAL(18, 2),
UNIT_PRICE DECIMAL(18, 4) NOT NULL,
CONSTRAINT PK_TIERED_BILLING_RULE PRIMARY KEY (TIER_ID)
);

CREATE INDEX IDX_TIERED_RULE ON TIERED_BILLING_RULE(RULE_ID, MIN_VALUE);

# 计费记录表
CREATE TABLE BILLING_RECORD (
RECORD_ID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
CUSTOMER_ID VARCHAR(32) NOT NULL,
SERVICE_ID VARCHAR(32) NOT NULL,
RULE_ID VARCHAR(32) NOT NULL,
USAGE_VALUE DECIMAL(18, 2) NOT NULL,
BILLING_AMOUNT DECIMAL(18, 2) NOT NULL,
BILLING_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
BILLING_PERIOD VARCHAR(20) NOT NULL,
CONSTRAINT PK_BILLING_RECORD PRIMARY KEY (RECORD_ID)
) PARTITION BY RANGE (BILLING_TIME)
(
PARTITION P202604 STARTING ‘2026-04-01’ ENDING ‘2026-04-30’
);

CREATE INDEX IDX_BILLING_CUSTOMER ON BILLING_RECORD(CUSTOMER_ID, BILLING_TIME DESC);
CREATE INDEX IDX_BILLING_SERVICE ON BILLING_RECORD(SERVICE_ID, BILLING_TIME DESC);

# 账单表
CREATE TABLE BILLING_INVOICE (
INVOICE_ID VARCHAR(32) NOT NULL,
CUSTOMER_ID VARCHAR(32) NOT NULL,
BILLING_PERIOD VARCHAR(20) NOT NULL,
TOTAL_AMOUNT DECIMAL(18, 2) NOT NULL,
PAID_AMOUNT DECIMAL(18, 2) DEFAULT 0,
INVOICE_STATUS VARCHAR(20) NOT NULL DEFAULT ‘UNPAID’,
CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
DUE_DATE DATE NOT NULL,
CONSTRAINT PK_BILLING_INVOICE PRIMARY KEY (INVOICE_ID)
);

CREATE INDEX IDX_INVOICE_CUSTOMER ON BILLING_INVOICE(CUSTOMER_ID, BILLING_PERIOD);

2.2 套餐表设计

# 套餐定义表
CREATE TABLE SERVICE_PACKAGE (
PACKAGE_ID VARCHAR(32) NOT NULL,
PACKAGE_NAME VARCHAR(100) NOT NULL,
PACKAGE_TYPE VARCHAR(20) NOT NULL,
MONTHLY_FEE DECIMAL(18, 2) NOT NULL,
INCLUDED_USAGE DECIMAL(18, 2) DEFAULT 0,
OVERAGE_PRICE DECIMAL(18, 4),
EFFECTIVE_DATE DATE NOT NULL,
EXPIRE_DATE DATE,
IS_ACTIVE CHAR(1) DEFAULT ‘Y’,
CONSTRAINT PK_SERVICE_PACKAGE PRIMARY KEY (PACKAGE_ID)
);

# 客户套餐订阅表
CREATE TABLE CUSTOMER_PACKAGE (
SUBSCRIPTION_ID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
CUSTOMER_ID VARCHAR(32) NOT NULL,
PACKAGE_ID VARCHAR(32) NOT NULL,
SUBSCRIBE_DATE DATE NOT NULL,
UNSUBSCRIBE_DATE DATE,
STATUS VARCHAR(20) NOT NULL DEFAULT ‘ACTIVE’,
CONSTRAINT PK_CUSTOMER_PACKAGE PRIMARY KEY (SUBSCRIPTION_ID)
);

CREATE INDEX IDX_CUSTOMER_PACKAGE ON CUSTOMER_PACKAGE(CUSTOMER_ID, STATUS);

Part03-计费规则实现

3.1 计费计算存储过程

# 计费计算存储过程
CREATE OR REPLACE PROCEDURE SP_CALCULATE_BILLING(
IN p_customer_id VARCHAR(32),
IN p_service_id VARCHAR(32),
IN p_usage_value DECIMAL(18, 2),
IN p_billing_period VARCHAR(20),
OUT p_billing_amount DECIMAL(18, 2)
)
LANGUAGE SQL
BEGIN
DECLARE v_rule_id VARCHAR(32);
DECLARE v_rule_type VARCHAR(20);
DECLARE v_unit_price DECIMAL(18, 4);
DECLARE v_min_charge DECIMAL(18, 2);
DECLARE v_max_charge DECIMAL(18, 2);
DECLARE v_package_id VARCHAR(32);
DECLARE v_included_usage DECIMAL(18, 2);
DECLARE v_overage_price DECIMAL(18, 4);

SET p_billing_amount = 0;

— 检查客户套餐
SELECT P.PACKAGE_ID, P.INCLUDED_USAGE, P.OVERAGE_PRICE
INTO v_package_id, v_included_usage, v_overage_price
FROM CUSTOMER_PACKAGE CP
JOIN SERVICE_PACKAGE P ON CP.PACKAGE_ID = P.PACKAGE_ID
WHERE CP.CUSTOMER_ID = p_customer_id
AND CP.STATUS = ‘ACTIVE’
AND CURRENT DATE BETWEEN CP.SUBSCRIBE_DATE AND COALESCE(CP.UNSUBSCRIBE_DATE, ‘9999-12-31’);

IF v_package_id IS NOT NULL THEN
— 套餐计费
IF p_usage_value <= v_included_usage THEN SET p_billing_amount = 0; ELSE SET p_billing_amount = (p_usage_value - v_included_usage) * v_overage_price; END IF; ELSE -- 获取计费规则 SELECT RULE_ID, RULE_TYPE, UNIT_PRICE, MIN_CHARGE, MAX_CHARGE INTO v_rule_id, v_rule_type, v_unit_price, v_min_charge, v_max_charge FROM BILLING_RULE WHERE RULE_TYPE = 'STANDARD' AND IS_ACTIVE = 'Y' AND CURRENT DATE BETWEEN EFFECTIVE_DATE AND COALESCE(EXPIRE_DATE, '9999-12-31') FETCH FIRST 1 ROW ONLY; -- 计算费用 SET p_billing_amount = p_usage_value * v_unit_price; -- 应用最低收费 IF p_billing_amount < v_min_charge THEN SET p_billing_amount = v_min_charge; END IF; -- 应用最高收费 IF v_max_charge IS NOT NULL AND p_billing_amount > v_max_charge THEN
SET p_billing_amount = v_max_charge;
END IF;
END IF;

— 插入计费记录
INSERT INTO BILLING_RECORD (
CUSTOMER_ID, SERVICE_ID, RULE_ID,
USAGE_VALUE, BILLING_AMOUNT, BILLING_PERIOD
) VALUES (
p_customer_id, p_service_id, v_rule_id,
p_usage_value, p_billing_amount, p_billing_period
);
END;

3.2 阶梯计费实现

# 阶梯计费存储过程
CREATE OR REPLACE PROCEDURE SP_TIERED_BILLING(
IN p_customer_id VARCHAR(32),
IN p_service_id VARCHAR(32),
IN p_usage_value DECIMAL(18, 2),
IN p_billing_period VARCHAR(20),
OUT p_billing_amount DECIMAL(18, 2)
)
LANGUAGE SQL
BEGIN
DECLARE v_rule_id VARCHAR(32);
DECLARE v_tier_price DECIMAL(18, 4);
DECLARE v_min_value DECIMAL(18, 2);
DECLARE v_max_value DECIMAL(18, 2);
DECLARE v_remaining_usage DECIMAL(18, 2);
DECLARE v_tier_usage DECIMAL(18, 2);

SET p_billing_amount = 0;
SET v_remaining_usage = p_usage_value;

— 获取阶梯计费规则
FOR tier_cursor AS
SELECT RULE_ID, MIN_VALUE, MAX_VALUE, UNIT_PRICE
FROM TIERED_BILLING_RULE
WHERE RULE_ID = (
SELECT RULE_ID FROM BILLING_RULE
WHERE RULE_TYPE = ‘TIERED’
AND IS_ACTIVE = ‘Y’
AND CURRENT DATE BETWEEN EFFECTIVE_DATE AND COALESCE(EXPIRE_DATE, ‘9999-12-31’)
FETCH FIRST 1 ROW ONLY
)
ORDER BY MIN_VALUE
DO
IF v_remaining_usage > 0 THEN
SET v_tier_usage = tier_cursor.MAX_VALUE – tier_cursor.MIN_VALUE;

IF v_remaining_usage <= v_tier_usage THEN SET p_billing_amount = p_billing_amount + v_remaining_usage * tier_cursor.UNIT_PRICE; SET v_remaining_usage = 0; ELSE SET p_billing_amount = p_billing_amount + v_tier_usage * tier_cursor.UNIT_PRICE; SET v_remaining_usage = v_remaining_usage - v_tier_usage; END IF; END IF; END FOR; -- 插入计费记录 INSERT INTO BILLING_RECORD ( CUSTOMER_ID, SERVICE_ID, RULE_ID, USAGE_VALUE, BILLING_AMOUNT, BILLING_PERIOD ) VALUES ( p_customer_id, p_service_id, v_rule_id, p_usage_value, p_billing_amount, p_billing_period ); END;

Part04-账单生成

4.1 账单生成存储过程

# 账单生成存储过程
CREATE OR REPLACE PROCEDURE SP_GENERATE_INVOICE(
IN p_customer_id VARCHAR(32),
IN p_billing_period VARCHAR(20),
OUT p_invoice_id VARCHAR(32),
OUT p_total_amount DECIMAL(18, 2)
)
LANGUAGE SQL
BEGIN
SET p_invoice_id = ‘INV’ || TO_CHAR(CURRENT DATE, ‘YYYYMMDD’) ||
SUBSTR(TO_CHAR(RAND() * 10000), 1, 4);

— 计算总金额
SELECT SUM(BILLING_AMOUNT) INTO p_total_amount
FROM BILLING_RECORD
WHERE CUSTOMER_ID = p_customer_id
AND BILLING_PERIOD = p_billing_period;

— 创建账单
INSERT INTO BILLING_INVOICE (
INVOICE_ID, CUSTOMER_ID, BILLING_PERIOD,
TOTAL_AMOUNT, DUE_DATE
) VALUES (
p_invoice_id, p_customer_id, p_billing_period,
p_total_amount, CURRENT DATE + 15 DAYS
);
END;

# 批量生成账单
CREATE OR REPLACE PROCEDURE SP_BATCH_GENERATE_INVOICE(
IN p_billing_period VARCHAR(20)
)
LANGUAGE SQL
BEGIN
DECLARE v_customer_id VARCHAR(32);
DECLARE v_invoice_id VARCHAR(32);
DECLARE v_total_amount DECIMAL(18, 2);

FOR customer_cursor AS
SELECT DISTINCT CUSTOMER_ID
FROM BILLING_RECORD
WHERE BILLING_PERIOD = p_billing_period
DO
CALL SP_GENERATE_INVOICE(
customer_cursor.CUSTOMER_ID,
p_billing_period,
v_invoice_id,
v_total_amount
);
END FOR;
END;

4.2 账单查询

# 查询客户账单
SELECT
I.INVOICE_ID,
I.CUSTOMER_ID,
I.BILLING_PERIOD,
I.TOTAL_AMOUNT,
I.PAID_AMOUNT,
I.INVOICE_STATUS,
I.DUE_DATE
FROM BILLING_INVOICE I
WHERE I.CUSTOMER_ID = ?
ORDER BY I.CREATE_TIME DESC;

# 查询账单明细
SELECT
R.RECORD_ID,
R.SERVICE_ID,
R.RULE_ID,
R.USAGE_VALUE,
R.BILLING_AMOUNT,
R.BILLING_TIME
FROM BILLING_RECORD R
WHERE R.CUSTOMER_ID = ?
AND R.BILLING_PERIOD = ?
ORDER BY R.BILLING_TIME;

# 统计账单金额
SELECT
BILLING_PERIOD,
COUNT(*) AS INVOICE_COUNT,
SUM(TOTAL_AMOUNT) AS TOTAL_AMOUNT,
SUM(PAID_AMOUNT) AS PAID_AMOUNT,
SUM(TOTAL_AMOUNT – PAID_AMOUNT) AS UNPAID_AMOUNT
FROM BILLING_INVOICE
GROUP BY BILLING_PERIOD
ORDER BY BILLING_PERIOD DESC;

Part05-风哥经验总结与分享

5.1 计费系统设计要点

  • 设计灵活的计费规则
  • 支持多种计费模式
  • 确保计费准确性
  • 建立完善的账单流程
  • 支持账单查询和统计
  • 建立计费审计机制

5.2 设计建议

计费类型 适用场景 注意事项
按时长 通话、视频 精确计费
按流量 数据传输 流量统计准确
阶梯计费 用量波动大 规则清晰

5.3 运维要点

  • 定期验证计费准确性
  • 定期检查账单生成
  • 监控计费系统性能
  • 定期清理历史数据
  • 建立计费监控告警
  • 持续优化计费流程
更多视频教程www.fgedu.net.cn
学习交流加群风哥微信: itpux-com
风哥Oracle/MySQL/PostgreSQL/Greenplum/DB2/Redis等数据库培训课程,10年一线实战经验,企业级培训,真正掌握数据库核心技术!

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息