Files
Omni_orm.db/orm_api_kernel_v2.txt
2026-02-06 14:31:07 +08:00

345 lines
11 KiB
Plaintext

DELIMITER //
CREATE OR REPLACE PROCEDURE orm_api_kernel_v2(
IN p_tablename VARCHAR(100),
IN p_pk VARCHAR(100), -- primary key(for update delete)
IN p_action VARCHAR(20), -- CRUD
IN p_uuid VARCHAR(100),
IN p_json_id INT
)
/*
Function : 通用 orm-api 根据传入参数及设定,智能生成相应SQL
Description: 模仿 ORM 设定,让前端程序只需传入参数就能执行增删查改基本功能
Build Date : 2024-03-20
call orm_api_kernel_v2('pms_sprint','sprintid','U','uuid-20250803_2',0);
Modify History
Item Who Date Modify Docs
==== ========== ========== ================================================
1 Developer 2024/03/20 从 MS-SQL v2 版本转换为 MariaDB 版本并优化
*/
BEGIN
DECLARE v_field_identity VARCHAR(100);
DECLARE v_fields TEXT;
DECLARE v_datas TEXT;
DECLARE v_updatedatas TEXT;
DECLARE v_pkwhere TEXT;
DECLARE v_sql LONGTEXT;
DECLARE v_pk_cnt INT;
DECLARE v_pk_no INT;
DECLARE v_max_no VARCHAR(20);
DECLARE v_bill_uuid VARCHAR(100);
DECLARE v_bill_head VARCHAR(20);
DECLARE v_middlefield VARCHAR(100);
DECLARE v_dest_table VARCHAR(100);
DECLARE v_pk_id VARCHAR(50);
DECLARE v_fieldname VARCHAR(100);
DECLARE v_contents LONGTEXT;
DECLARE v_fieldtype VARCHAR(20);
DECLARE v_quot CHAR(1);
DECLARE v_cnt INT;
DECLARE v_cnt2 INT;
DECLARE v_maxcount INT;
DECLARE v_currid INT;
DECLARE v_nextrowid INT;
DECLARE v_crlf VARCHAR(2);
-- 创建临时表存储JSON数据
CREATE TEMPORARY TABLE IF NOT EXISTS temp_jsondata (
parent_id INT,
json_key VARCHAR(100),
json_value LONGTEXT,
ValueType VARCHAR(20),
rowid INT AUTO_INCREMENT PRIMARY KEY
);
-- 临时表用于同步删除
CREATE TEMPORARY TABLE IF NOT EXISTS temp_sync_del (
dest_table VARCHAR(100),
pk_id VARCHAR(50),
rowid INT AUTO_INCREMENT PRIMARY KEY
);
-- 临时表用于避免重复字段名
CREATE TEMPORARY TABLE IF NOT EXISTS temp_comp_json (
fieldname VARCHAR(100)
);
-- 清空临时表
TRUNCATE TABLE temp_jsondata;
TRUNCATE TABLE temp_sync_del;
TRUNCATE TABLE temp_comp_json;
-- 将传入参数转为JSON数据(多筆 Grid 資料寫入)
IF p_json_id = 1 then
INSERT INTO temp_jsondata (parent_id, json_key, json_value, ValueType)
SELECT parent_id, json_key, json_value, ValueType
FROM orm_json_tmp
WHERE uuid = p_uuid;
else
INSERT INTO temp_jsondata (parent_id, json_key, json_value, ValueType)
SELECT parent_id, json_key, json_value, ValueType
FROM orm_json_tmp
WHERE uuid = p_uuid AND parent_id = FLOOR(p_json_id / 1000) and object_id = p_json_id - FLOOR(p_json_id / 1000)*1000;
end if;
-- 获取自增字段
SELECT COLUMN_NAME INTO v_field_identity
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = p_tablename
AND EXTRA = 'auto_increment'
LIMIT 1;
-- 初始化变量
SET v_fields = '';
SET v_datas = '';
SET v_pkwhere = '';
SET v_updatedatas = '';
SET v_pk_cnt = 0;
SET v_bill_uuid = '';
SET v_bill_head = '';
SET v_crlf = CONCAT(CHAR(13), CHAR(10));
-- 获取记录数
SELECT COUNT(*) INTO v_maxcount FROM temp_jsondata;
SELECT MIN(rowid) INTO v_currid FROM temp_jsondata;
-- 遍历JSON数据构建SQL
WHILE v_currid <= v_maxcount DO
-- 获取当前记录
SELECT json_key, IFNULL(json_value, ''), ValueType
INTO v_fieldname, v_contents, v_fieldtype
FROM temp_jsondata
WHERE rowid = v_currid;
-- 设置引号
IF lower(v_fieldtype) = 'string' THEN
SET v_quot = '''';
ELSE
SET v_quot = '';
END IF;
-- 记录billno和uuid用于MD更新
IF v_fieldname = 'uuid' THEN
SET v_bill_uuid = v_contents;
END IF;
IF v_fieldname = 'billno' THEN
SET v_bill_head = v_contents;
END IF;
-- 检查字段是否存在
SELECT COUNT(*) INTO v_cnt
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = p_tablename AND COLUMN_NAME = v_fieldname;
SELECT COUNT(*) INTO v_cnt2
FROM temp_comp_json
WHERE fieldname = v_fieldname;
-- 如果字段存在且未处理过
IF v_cnt > 0 AND v_cnt2 <= 0 THEN
-- 记录主键内容
SELECT COUNT(*) INTO v_pk_no
FROM (
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(p_pk, ',', numbers.n), ',', -1) AS col
FROM (
SELECT 1 AS n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL
SELECT 4 UNION ALL SELECT 5 -- 假设最多5个主键字段
) numbers
WHERE numbers.n <= LENGTH(p_pk) - LENGTH(REPLACE(p_pk, ',', '')) + 1
) AS split_pk
WHERE col = v_fieldname;
IF v_pk_no > 0 THEN
IF v_pk_cnt >= 1 THEN
UPDATE sys_transaction SET para02 = v_contents WHERE tablename = p_tablename;
ELSE
UPDATE sys_transaction SET para01 = v_contents WHERE tablename = p_tablename;
END IF;
SET v_pk_cnt = v_pk_cnt + 1;
END IF;
-- 非自增字段处理
IF IFNULL(v_field_identity, '') <> v_fieldname THEN
SET v_fields = CONCAT(v_fields, v_fieldname, ',');
-- 构建INSERT值
IF p_action = 'C' OR p_action = 'Insert' THEN
SET v_datas = CONCAT(v_datas, v_quot, v_contents, v_quot, ',');
END IF;
END IF;
-- 构建UPDATE语句
IF (p_action = 'U' OR p_action = 'Update') AND v_pk_no = 0 THEN
-- 处理日期格式
IF SUBSTRING(v_contents, 11, 19) = 'T08:00:00.000+08:00' THEN
SET v_contents = SUBSTRING(v_contents, 1, 10);
END IF;
SET v_updatedatas = CONCAT(v_updatedatas, v_fieldname, ' = ', v_quot, v_contents, v_quot, ',');
END IF;
-- 构建WHERE条件
IF v_pk_no > 0 THEN
SET v_pkwhere = CONCAT(v_pkwhere, v_fieldname, ' = ', v_quot, v_contents, v_quot, ' AND ');
END IF;
END IF;
-- 记录已处理字段
INSERT INTO temp_comp_json VALUES (v_fieldname);
-- 获取下一行
SELECT MIN(rowid) INTO v_nextrowid
FROM temp_jsondata
WHERE rowid > v_currid;
SET v_currid = v_nextrowid;
END WHILE;
-- 处理没有主键的情况
IF v_pk_cnt = 0 THEN
SELECT middlefield INTO v_middlefield
FROM sys_transaction
WHERE tablename = p_tablename
LIMIT 1;
SELECT json_value INTO v_contents
FROM temp_jsondata
WHERE json_key = v_middlefield
LIMIT 1;
IF LENGTH(v_contents) <= 1000 THEN
UPDATE sys_transaction SET para01 = v_contents WHERE tablename = p_tablename;
END IF;
END IF;
-- 处理自增主键情况
IF (p_action = 'C' OR p_action = 'Insert') AND (p_pk = v_field_identity) THEN
UPDATE sys_transaction SET para01 = 'identity' WHERE tablename = p_tablename;
END IF;
-- 移除末尾的逗号或AND
IF v_fields <> '' THEN
-- SET v_fields = SUBSTRING(v_fields, 1, LENGTH(v_fields) - 1);
SET v_fields = TRIM(TRAILING ',' FROM v_fields);
END IF;
IF v_datas <> '' THEN
-- SET v_datas = SUBSTRING(v_datas, 1, LENGTH(v_datas) - 1);
SET v_datas = TRIM(TRAILING ',' FROM v_datas);
END IF;
IF v_updatedatas <> '' THEN
-- SET v_updatedatas = SUBSTRING(v_updatedatas, 1, LENGTH(v_updatedatas) - 1);
SET v_updatedatas = TRIM(TRAILING ',' FROM v_updatedatas);
END IF;
IF v_pkwhere <> '' THEN
SET v_pkwhere = SUBSTRING(v_pkwhere, 1, LENGTH(v_pkwhere) - 5);
END IF;
-- 构建基础SQL
IF p_action = 'C' OR p_action = 'Insert' THEN
SET v_sql = CONCAT('INSERT INTO ', p_tablename, ' (', v_fields, ') VALUES (', v_datas, ')');
-- 加入 M-D 的 D 同步 billno update
INSERT INTO temp_sync_del (dest_table, pk_id)
SELECT dest_table, pk_id FROM sys_sync_delete_detail WHERE tablename = p_tablename;
-- 处理同步更新
SELECT COUNT(*) INTO v_maxcount FROM temp_sync_del;
SELECT MIN(rowid) INTO v_currid FROM temp_sync_del;
WHILE v_currid <= v_maxcount DO
SELECT dest_table, pk_id INTO v_dest_table, v_pk_id
FROM temp_sync_del
WHERE rowid = v_currid;
-- 检查目标表是否有uuid字段
SELECT COUNT(*) INTO v_cnt
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = v_dest_table AND COLUMN_NAME = 'uuid';
IF v_cnt > 0 THEN
SET v_sql = CONCAT(v_sql, ';\n',
'UPDATE ', v_dest_table, ' SET ', IFNULL(v_pk_id, 'billno'), ' = ''',
v_bill_head, ''' WHERE uuid = ''', v_bill_uuid, '''');
END IF;
-- 获取下一行
SELECT MIN(rowid) INTO v_nextrowid
FROM temp_sync_del
WHERE rowid > v_currid;
SET v_currid = v_nextrowid;
END WHILE;
ELSEIF p_action = 'U' OR p_action = 'Update' THEN
SET v_sql = CONCAT('UPDATE ', p_tablename, ' SET ', v_updatedatas, ' WHERE ', v_pkwhere);
ELSEIF p_action = 'D' OR p_action = 'Delete' THEN
-- 基础删除语句
SET v_sql = CONCAT('DELETE FROM ', p_tablename, ' WHERE ', v_pkwhere);
-- 处理同步删除
INSERT INTO temp_sync_del (dest_table, pk_id)
SELECT dest_table, pk_id FROM sys_sync_delete_detail WHERE tablename = p_tablename;
SELECT COUNT(*) INTO v_maxcount FROM temp_sync_del;
SELECT MIN(rowid) INTO v_currid FROM temp_sync_del;
WHILE v_currid <= v_maxcount DO
SELECT dest_table, pk_id INTO v_dest_table, v_pk_id
FROM temp_sync_del
WHERE rowid = v_currid;
-- 解决 M-D 的 pk 栏名不同的问题
IF IFNULL(v_pk_id, '') = '' THEN
SET v_sql = CONCAT(v_sql, ';', v_crlf,
'DELETE FROM ', v_dest_table, ' WHERE ', v_pkwhere, ';');
ELSE
SET v_sql = CONCAT(v_sql, ';', v_crlf,
'DELETE FROM ', v_dest_table, ' WHERE ',
REPLACE(v_pkwhere, p_pk, v_pk_id), ';');
END IF;
-- 获取下一行
SELECT MIN(rowid) INTO v_nextrowid
FROM temp_sync_del
WHERE rowid > v_currid;
SET v_currid = v_nextrowid;
END WHILE;
END IF;
-- 处理日期格式问题
IF INSTR(v_sql, '000+08:00') > 0 THEN
SET v_sql = REPLACE(v_sql, '000+08:00', '000Z');
END IF;
-- 执行SQL
/* Mariadb 不支援動態語句多 sql, 只能切割
GET DIAGNOSTICS CONDITION 1
@sqlstate = RETURNED_SQLSTATE, @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
SELECT 1 AS code, CONCAT('Error: ', @errno, ' (', @sqlstate, '): ', @text) AS msg, 0 AS recno;
SELECT v_sql AS error_sql;
END;
-- 返回成功结果
SELECT 0 AS code, 'ok' AS msg, 0 AS recno;
-- 执行SQL
SET @dynamic_sql = v_sql;
PREPARE stmt FROM @dynamic_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END;
*/
call execute_multiple_sql(v_sql);
-- 清理临时表
DROP TEMPORARY TABLE IF EXISTS temp_jsondata;
DROP TEMPORARY TABLE IF EXISTS temp_sync_del;
DROP TEMPORARY TABLE IF EXISTS temp_comp_json;
END //
DELIMITER ;