-- BMS 应收 V1.0 -- -- 需求文档中的来源表 prc_bill / prc_bill_fee 在本项目已经由 -- sql/price/rename_bill_tables.sql 迁移为 prc_order_bill / prc_income_bill_fee; -- 本脚本只创建正式应收表,不改动来源表及其 VARCHAR(36) 主键。 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; CREATE TABLE IF NOT EXISTS ar_bill ( ar_bill_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '应收账单ID', bill_no VARCHAR(50) NOT NULL COMMENT '账单号', bill_name VARCHAR(100) NOT NULL COMMENT '账单名称', customer_id BIGINT(20) NOT NULL COMMENT '客户ID', customer_code VARCHAR(50) NOT NULL COMMENT '客户编码快照', customer_name VARCHAR(100) NOT NULL COMMENT '客户名称快照', bill_period_start DATE NOT NULL COMMENT '账期开始日', bill_period_end DATE NOT NULL COMMENT '账期结束日', bill_date DATE NOT NULL COMMENT '账单出具日期', currency VARCHAR(10) NOT NULL DEFAULT 'CNY' COMMENT '币种', order_count INT(11) NOT NULL DEFAULT 0 COMMENT '订单数量', total_amount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '账单应收总额', written_off_amount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '已核销金额缓存', unwritten_amount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '未核销金额缓存', status VARCHAR(30) NOT NULL COMMENT '状态:DRAFT=草稿,CONFIRMED=已确认,PARTIAL_WRITTEN_OFF=部分核销,WRITTEN_OFF=已核销,VOID=已作废', generation_status VARCHAR(20) NOT NULL DEFAULT 'READY' COMMENT '生成状态:GENERATING=生成中,READY=可用,FAILED=生成失败', bill_version INT(11) NOT NULL DEFAULT 1 COMMENT '账单版本', bank_account_name VARCHAR(100) DEFAULT NULL COMMENT '收款账户名称快照', bank_account_no VARCHAR(128) DEFAULT NULL COMMENT '收款账号快照,应用层脱敏展示', bank_name VARCHAR(100) DEFAULT NULL COMMENT '开户行快照', remark VARCHAR(500) DEFAULT NULL COMMENT '备注或作废原因', confirmed_by VARCHAR(64) DEFAULT NULL COMMENT '确认人', confirmed_time DATETIME DEFAULT NULL COMMENT '确认时间', create_by VARCHAR(64) NOT NULL COMMENT '创建人', create_time DATETIME NOT NULL COMMENT '创建时间', update_by VARCHAR(64) NOT NULL COMMENT '更新人', update_time DATETIME NOT NULL COMMENT '更新时间', PRIMARY KEY (ar_bill_id), UNIQUE KEY uk_ar_bill_no (bill_no), UNIQUE KEY uk_ar_bill_customer_cutoff_version (customer_id, currency, bill_period_end, bill_version), KEY idx_ar_bill_customer_cutoff (customer_id, currency, bill_period_end), KEY idx_ar_bill_status (status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='正式应收账单主表'; CREATE TABLE IF NOT EXISTS ar_bill_generate_task ( task_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '生成任务ID', task_no VARCHAR(50) NOT NULL COMMENT '生成任务编号', ar_bill_id BIGINT(20) NOT NULL COMMENT '应收账单ID', selection_mode VARCHAR(20) NOT NULL COMMENT '选择模式:EXPLICIT=手动选择,ALL_MATCHED=全选查询结果', request_payload LONGTEXT NOT NULL COMMENT '生成请求快照JSON', snapshot_create_time DATETIME DEFAULT NULL COMMENT '来源订单创建时间快照', last_source_bill_id VARCHAR(36) DEFAULT NULL COMMENT '来源订单游标', total_count INT(11) NOT NULL DEFAULT -1 COMMENT '待处理订单数,-1表示尚未统计', processed_count INT(11) NOT NULL DEFAULT 0 COMMENT '已处理订单数', success_count INT(11) NOT NULL DEFAULT 0 COMMENT '成功订单数', total_amount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '当前生成金额', status VARCHAR(30) NOT NULL COMMENT '任务状态:WAITING=待处理,RUNNING=生成中,SUCCESS=生成成功,FAILED=生成失败,CANCEL_REQUESTED=取消中,CANCELED=已取消', error_message VARCHAR(1000) DEFAULT NULL COMMENT '错误信息', request_token VARCHAR(64) NOT NULL COMMENT '请求幂等标识', create_by VARCHAR(64) NOT NULL COMMENT '创建人', create_time DATETIME NOT NULL COMMENT '创建时间', started_at DATETIME DEFAULT NULL COMMENT '开始时间', heartbeat_time DATETIME DEFAULT NULL COMMENT '最近心跳时间', finished_at DATETIME DEFAULT NULL COMMENT '完成时间', PRIMARY KEY (task_id), UNIQUE KEY uk_ar_bill_generate_task_no (task_no), UNIQUE KEY uk_ar_bill_generate_request_token (request_token), KEY idx_ar_bill_generate_status (status, create_time), KEY idx_ar_bill_generate_creator (create_by, status, create_time), KEY idx_ar_bill_generate_bill (ar_bill_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='应收账单异步生成任务'; CREATE TABLE IF NOT EXISTS ar_bill_detail ( detail_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '账单订单明细ID', ar_bill_id BIGINT(20) NOT NULL COMMENT '应收账单ID', prc_order_bill_id VARCHAR(36) NOT NULL COMMENT '来源计费订单ID,对应 prc_order_bill.bill_id', detail_no INT(11) NOT NULL COMMENT '账单内顺序号', order_no VARCHAR(64) NOT NULL COMMENT '订单号快照', tracking_no VARCHAR(64) DEFAULT NULL COMMENT '运单号快照', transfer_no VARCHAR(64) DEFAULT NULL COMMENT '转单号快照', receive_time DATETIME DEFAULT NULL COMMENT '收件或入库时间', product_code VARCHAR(50) NOT NULL COMMENT '产品代码快照', product_name VARCHAR(100) DEFAULT NULL COMMENT '产品名称快照', goods_description VARCHAR(500) DEFAULT NULL COMMENT '货物描述快照', country_code CHAR(2) DEFAULT NULL COMMENT '目的国家二字码', country_name VARCHAR(50) DEFAULT NULL COMMENT '目的国家名称', dest_postcode VARCHAR(20) DEFAULT NULL COMMENT '目的邮编', actual_weight DECIMAL(12,3) DEFAULT NULL COMMENT '实际重量KG', volume_weight DECIMAL(12,3) DEFAULT NULL COMMENT '材积重量KG', charge_weight DECIMAL(12,3) DEFAULT NULL COMMENT '计费重量KG', pkg_length DECIMAL(10,2) DEFAULT NULL COMMENT '长度CM', pkg_width DECIMAL(10,2) DEFAULT NULL COMMENT '宽度CM', pkg_height DECIMAL(10,2) DEFAULT NULL COMMENT '高度CM', currency VARCHAR(10) NOT NULL COMMENT '币种快照', total_amount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '订单费用合计', remark VARCHAR(500) DEFAULT NULL COMMENT '订单账单备注', create_by VARCHAR(64) NOT NULL COMMENT '创建人', create_time DATETIME NOT NULL COMMENT '创建时间', PRIMARY KEY (detail_id), UNIQUE KEY uk_ar_bill_detail_source (ar_bill_id, prc_order_bill_id), UNIQUE KEY uk_ar_bill_detail_no (ar_bill_id, detail_no), KEY idx_ar_bill_detail_source (prc_order_bill_id), KEY idx_ar_bill_detail_bill_transfer_no (ar_bill_id, transfer_no), CONSTRAINT fk_ar_bill_detail_bill FOREIGN KEY (ar_bill_id) REFERENCES ar_bill (ar_bill_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='应收账单订单快照'; CREATE TABLE IF NOT EXISTS ar_bill_detail_fee ( detail_fee_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '账单费用明细ID', detail_id BIGINT(20) NOT NULL COMMENT '账单订单明细ID', prc_income_bill_fee_id VARCHAR(36) NOT NULL COMMENT '来源收入费用ID,对应 prc_income_bill_fee.fee_id', fee_no INT(11) NOT NULL COMMENT '订单内费用顺序号', fee_type VARCHAR(30) NOT NULL COMMENT '费用类型快照', fee_name VARCHAR(100) DEFAULT NULL COMMENT '费用名称快照', sc_id BIGINT(20) DEFAULT NULL COMMENT '附加费配置ID快照', quantity DECIMAL(12,3) DEFAULT NULL COMMENT '计费数量', unit VARCHAR(20) DEFAULT NULL COMMENT '计费单位', unit_price DECIMAL(15,4) DEFAULT NULL COMMENT '费用单价', amount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '费用金额', currency VARCHAR(10) NOT NULL COMMENT '币种', calculation_formula VARCHAR(500) DEFAULT NULL COMMENT '计算公式或说明', round_mode VARCHAR(20) DEFAULT NULL COMMENT '取舍规则', remark VARCHAR(500) DEFAULT NULL COMMENT '费用备注', create_by VARCHAR(64) NOT NULL COMMENT '创建人', create_time DATETIME NOT NULL COMMENT '创建时间', PRIMARY KEY (detail_fee_id), UNIQUE KEY uk_ar_detail_prc_income_fee (detail_id, prc_income_bill_fee_id), KEY idx_ar_detail_fee_type (fee_type), KEY idx_ar_detail_prc_income_fee (prc_income_bill_fee_id), KEY idx_ar_detail_fee_order (detail_id, fee_no, detail_fee_id), CONSTRAINT fk_ar_detail_fee_detail FOREIGN KEY (detail_id) REFERENCES ar_bill_detail (detail_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='应收账单费用快照'; CREATE TABLE IF NOT EXISTS ar_export_template ( template_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '导出模板ID', template_code VARCHAR(50) NOT NULL COMMENT '模板编码,例如 AR_CUSTOMER_BILL', template_name VARCHAR(100) NOT NULL COMMENT '模板名称', business_type VARCHAR(50) NOT NULL COMMENT '业务类型,例如 AR_BILL', template_version VARCHAR(50) NOT NULL COMMENT '模板版本,已启用版本不可覆盖', storage_type VARCHAR(20) NOT NULL DEFAULT 'CLASSPATH' COMMENT '存储类型:CLASSPATH=应用内置资源,FILE=服务器文件,OSS=对象存储,MINIO=MinIO对象存储', storage_key VARCHAR(500) NOT NULL COMMENT '模板文件存储Key或classpath资源路径', file_hash VARCHAR(128) DEFAULT NULL COMMENT '模板文件SHA-256校验值', status VARCHAR(20) NOT NULL DEFAULT 'ENABLED' COMMENT '状态:ENABLED=启用,DISABLED=停用', is_default CHAR(1) NOT NULL DEFAULT '0' COMMENT '是否默认模板:1是0否', effective_start DATE DEFAULT NULL COMMENT '生效开始日期', effective_end DATE DEFAULT NULL COMMENT '生效结束日期', remark VARCHAR(500) DEFAULT NULL COMMENT '备注', create_by VARCHAR(64) NOT NULL COMMENT '创建人', create_time DATETIME NOT NULL COMMENT '创建时间', update_by VARCHAR(64) DEFAULT NULL COMMENT '更新人', update_time DATETIME DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (template_id), UNIQUE KEY uk_ar_export_template_code_version (business_type, template_code, template_version), KEY idx_ar_export_template_default (business_type, status, is_default, effective_start, effective_end) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='应收账单导出模板管理'; INSERT INTO ar_export_template ( template_code, template_name, business_type, template_version, storage_type, storage_key, file_hash, status, is_default, create_by, create_time, remark ) SELECT 'AR_CUSTOMER_BILL', '应收账单默认模板', 'AR_BILL', '1.0', 'CLASSPATH', 'templates/ar/ar_bill_template.xlsx', '735002ac3561e0579b724c0612a2c5ce2d6725bc7fd39c450b0aeff70911a45e', 'ENABLED', '1', 'system', NOW(), '系统内置默认模板' WHERE NOT EXISTS ( SELECT 1 FROM ar_export_template WHERE business_type = 'AR_BILL' AND template_code = 'AR_CUSTOMER_BILL' AND template_version = '1.0' ); CREATE TABLE IF NOT EXISTS ar_bill_export ( export_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '导出ID', ar_bill_id BIGINT(20) NOT NULL COMMENT '应收账单ID', file_name VARCHAR(255) NOT NULL COMMENT '下载展示名称', file_type VARCHAR(20) NOT NULL COMMENT 'XLSX/PDF', template_id BIGINT(20) DEFAULT NULL COMMENT '提交导出任务时绑定的模板ID', template_code VARCHAR(50) NOT NULL COMMENT '导出模板标识', template_version VARCHAR(50) DEFAULT NULL COMMENT '模板版本', template_storage_type VARCHAR(20) DEFAULT NULL COMMENT '绑定模板存储类型', template_storage_key VARCHAR(500) DEFAULT NULL COMMENT '绑定模板存储Key', template_hash VARCHAR(128) DEFAULT NULL COMMENT '绑定模板SHA-256校验值', storage_key VARCHAR(500) NOT NULL COMMENT '对象存储或本地文件Key', file_size BIGINT(20) DEFAULT NULL COMMENT '文件字节数', file_hash VARCHAR(128) DEFAULT NULL COMMENT 'SHA-256校验值', row_count INT(11) DEFAULT NULL COMMENT '导出订单行数', export_status VARCHAR(30) NOT NULL COMMENT '导出状态:PROCESSING=生成中,SUCCESS=成功(可下载),FAILED=失败', export_by VARCHAR(64) NOT NULL COMMENT '导出人', export_time DATETIME NOT NULL COMMENT '导出时间', remark VARCHAR(500) DEFAULT NULL COMMENT '失败原因或备注', PRIMARY KEY (export_id), KEY idx_ar_bill_export_bill (ar_bill_id, export_time), KEY idx_ar_bill_export_template (template_id), KEY idx_ar_bill_export_status (export_status), CONSTRAINT fk_ar_bill_export_bill FOREIGN KEY (ar_bill_id) REFERENCES ar_bill (ar_bill_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='应收账单导出文件元数据'; CREATE TABLE IF NOT EXISTS ar_bill_log ( log_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '日志ID', ar_bill_id BIGINT(20) DEFAULT NULL COMMENT '账单ID', object_type VARCHAR(40) NOT NULL COMMENT '对象类型:BILL=应收账单,EXPORT=账单导出,BALANCE_WRITEOFF=余额核销;历史值可能包含已下线模块类型', object_id VARCHAR(64) NOT NULL COMMENT '通用对象ID', operation_type VARCHAR(40) NOT NULL COMMENT '操作类型:CREATE=生成账单,GENERATE=生成校验,CONFIRM=确认账单,VOID=作废账单,EXPORT=导出账单,BALANCE_WRITEOFF=余额核销,CANCEL_BALANCE_WRITEOFF=取消余额核销', operation_desc VARCHAR(500) DEFAULT NULL COMMENT '操作说明', from_status VARCHAR(30) DEFAULT NULL COMMENT '变更前状态', to_status VARCHAR(30) DEFAULT NULL COMMENT '变更后状态', before_data TEXT COMMENT '变更前安全快照', after_data TEXT COMMENT '变更后安全快照', operator_id VARCHAR(64) NOT NULL COMMENT '操作人ID', operator_name VARCHAR(100) DEFAULT NULL COMMENT '操作人名称', operation_source VARCHAR(30) NOT NULL COMMENT '操作来源:WEB=网页端,API=接口,JOB=定时任务,IMPORT=数据导入', request_id VARCHAR(64) DEFAULT NULL COMMENT '请求幂等标识', trace_id VARCHAR(64) DEFAULT NULL COMMENT '链路标识', result VARCHAR(20) NOT NULL COMMENT '执行结果:SUCCESS=成功,FAILED=失败', error_message VARCHAR(1000) DEFAULT NULL COMMENT '失败原因', client_ip VARCHAR(64) DEFAULT NULL COMMENT '来源IP', create_time DATETIME NOT NULL COMMENT '日志时间', PRIMARY KEY (log_id), KEY idx_ar_bill_log_bill (ar_bill_id, create_time), KEY idx_ar_bill_log_object (object_type, object_id, create_time), KEY idx_ar_bill_log_request (request_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='应收账单操作日志'; -- ============================================================ -- 兼容已执行旧版本脚本的增量补齐逻辑 -- 本文件是应收账单模块唯一数据库脚本,新库和存量库均可重复执行。 -- ============================================================ SET @ar_db_name := DATABASE(); -- 1. 异步生成任务依赖字段 SET @ar_has_generation_status := ( SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @ar_db_name AND TABLE_NAME = 'ar_bill' AND COLUMN_NAME = 'generation_status' ); SET @ar_sql := IF(@ar_has_generation_status = 0, 'ALTER TABLE ar_bill ADD COLUMN generation_status VARCHAR(20) NOT NULL DEFAULT ''READY'' COMMENT ''生成状态:GENERATING=生成中,READY=可用,FAILED=生成失败'' AFTER status', 'SELECT 1'); PREPARE ar_stmt FROM @ar_sql; EXECUTE ar_stmt; DEALLOCATE PREPARE ar_stmt; -- 异步生成任务状态增加中文含义,便于数据库运维和排查。 -- 已存在 status 时只修改定义,不重复新增;兼容历史上已创建但字段不完整的任务表。 SET @ar_has_task_status := ( SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @ar_db_name AND TABLE_NAME = 'ar_bill_generate_task' AND COLUMN_NAME = 'status' ); SET @ar_sql := IF(@ar_has_task_status = 0, 'ALTER TABLE ar_bill_generate_task ADD COLUMN status VARCHAR(30) NOT NULL COMMENT ''任务状态:WAITING=待处理,RUNNING=生成中,SUCCESS=生成成功,FAILED=生成失败,CANCEL_REQUESTED=取消中,CANCELED=已取消'' AFTER total_amount', 'ALTER TABLE ar_bill_generate_task MODIFY COLUMN status VARCHAR(30) NOT NULL COMMENT ''任务状态:WAITING=待处理,RUNNING=生成中,SUCCESS=生成成功,FAILED=生成失败,CANCEL_REQUESTED=取消中,CANCELED=已取消'''); PREPARE ar_stmt FROM @ar_sql; EXECUTE ar_stmt; DEALLOCATE PREPARE ar_stmt; UPDATE ar_bill SET generation_status = 'READY' WHERE generation_status IS NULL; -- 2. 为异步游标查询补充来源订单索引。 -- 来源表可能尚未由价格模块脚本创建,因此这里做存在性判断。 SET @ar_has_source_table := ( SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = @ar_db_name AND TABLE_NAME = 'prc_order_bill' ); SET @ar_has_source_cursor_index := ( SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = @ar_db_name AND TABLE_NAME = 'prc_order_bill' AND INDEX_NAME = 'idx_bill_ar_async_cursor' ); SET @ar_sql := IF(@ar_has_source_table = 1 AND @ar_has_source_cursor_index = 0, 'ALTER TABLE prc_order_bill ADD INDEX idx_bill_ar_async_cursor (customer_id, currency, ar_bill_status, create_time, bill_id)', 'SELECT 1'); PREPARE ar_stmt FROM @ar_sql; EXECUTE ar_stmt; DEALLOCATE PREPARE ar_stmt; -- 3. 兼容已存在的模板表和导出记录表,补齐模板字段、注释及索引。 ALTER TABLE ar_export_template MODIFY COLUMN storage_type VARCHAR(20) NOT NULL DEFAULT 'CLASSPATH' COMMENT '存储类型:CLASSPATH=应用内置资源,FILE=服务器文件,OSS=对象存储,MINIO=MinIO对象存储', MODIFY COLUMN status VARCHAR(20) NOT NULL DEFAULT 'ENABLED' COMMENT '状态:ENABLED=启用,DISABLED=停用'; SET @ar_has_template_id := ( SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @ar_db_name AND TABLE_NAME = 'ar_bill_export' AND COLUMN_NAME = 'template_id' ); SET @ar_sql := IF(@ar_has_template_id = 0, 'ALTER TABLE ar_bill_export ADD COLUMN template_id BIGINT(20) DEFAULT NULL COMMENT ''提交导出任务时绑定的模板ID'' AFTER file_type', 'SELECT 1'); PREPARE ar_stmt FROM @ar_sql; EXECUTE ar_stmt; DEALLOCATE PREPARE ar_stmt; SET @ar_has_template_storage_type := ( SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @ar_db_name AND TABLE_NAME = 'ar_bill_export' AND COLUMN_NAME = 'template_storage_type' ); SET @ar_sql := IF(@ar_has_template_storage_type = 0, 'ALTER TABLE ar_bill_export ADD COLUMN template_storage_type VARCHAR(20) DEFAULT NULL COMMENT ''绑定模板存储类型'' AFTER template_version', 'SELECT 1'); PREPARE ar_stmt FROM @ar_sql; EXECUTE ar_stmt; DEALLOCATE PREPARE ar_stmt; SET @ar_has_template_storage_key := ( SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @ar_db_name AND TABLE_NAME = 'ar_bill_export' AND COLUMN_NAME = 'template_storage_key' ); SET @ar_sql := IF(@ar_has_template_storage_key = 0, 'ALTER TABLE ar_bill_export ADD COLUMN template_storage_key VARCHAR(500) DEFAULT NULL COMMENT ''绑定模板存储Key'' AFTER template_storage_type', 'SELECT 1'); PREPARE ar_stmt FROM @ar_sql; EXECUTE ar_stmt; DEALLOCATE PREPARE ar_stmt; SET @ar_has_template_hash := ( SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @ar_db_name AND TABLE_NAME = 'ar_bill_export' AND COLUMN_NAME = 'template_hash' ); SET @ar_sql := IF(@ar_has_template_hash = 0, 'ALTER TABLE ar_bill_export ADD COLUMN template_hash VARCHAR(128) DEFAULT NULL COMMENT ''绑定模板SHA-256校验值'' AFTER template_storage_key', 'SELECT 1'); PREPARE ar_stmt FROM @ar_sql; EXECUTE ar_stmt; DEALLOCATE PREPARE ar_stmt; SET @ar_has_template_index := ( SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = @ar_db_name AND TABLE_NAME = 'ar_bill_export' AND INDEX_NAME = 'idx_ar_bill_export_template' ); SET @ar_sql := IF(@ar_has_template_index = 0, 'ALTER TABLE ar_bill_export ADD INDEX idx_ar_bill_export_template (template_id)', 'SELECT 1'); PREPARE ar_stmt FROM @ar_sql; EXECUTE ar_stmt; DEALLOCATE PREPARE ar_stmt; SET FOREIGN_KEY_CHECKS = 1;