first commit

This commit is contained in:
DATAEXPRESS\4734
2026-02-06 14:31:07 +08:00
commit e7f672ddff
13 changed files with 1604 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
DELIMITER //
CREATE OR REPLACE PROCEDURE execute_multiple_sql(IN v_sql TEXT)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
@sqlstate = RETURNED_SQLSTATE,
@errno = MYSQL_ERRNO,
@text = MESSAGE_TEXT;
SELECT 1 AS code, CONCAT('Error: ', @errno, ' (', @sqlstate, '): ', @text) AS msg;
END;
-- 按分号分割并执行多条语句
SET @sql = v_sql;
WHILE LENGTH(@sql) > 0 DO
SET @statement = SUBSTRING_INDEX(@sql, ';', 1);
SET @sql = SUBSTRING(@sql, LENGTH(@statement) + 2);
IF LENGTH(TRIM(@statement)) > 0 THEN
PREPARE stmt FROM @statement;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END WHILE;
SELECT 0 AS code, 'ok' AS msg;
END//
DELIMITER ;
+67
View File
@@ -0,0 +1,67 @@
DELIMITER //
CREATE OR REPLACE FUNCTION gf_split(
p_source TEXT,
p_split VARCHAR(2)
) RETURNS TEXT
/*
function : 將傳入的字串, 依 p_split 切割為多筆資料, 傳回 table
description:
呼叫範例:
SELECT col FROM JSON_TABLE(gf_split('R,G,B',','), '$[*]'
COLUMNS(col VARCHAR(600) PATH '$.col')) t;
SELECT col FROM JSON_TABLE(gf_split('R,G,B',','), '$[*]'
COLUMNS(rowid int PATH '$.rowid', col VARCHAR(600) PATH '$.col')) t WHERE rowid = 1;
必須要有 CREATE TABLE _split( guid varchar(100), rowid INT, col varchar(600) );
https://www.sqlines.com/sql-server-to-mariadb/returns_table
build date : 2023/11/20
modify history
item who date modify docs
==== ========== ========== ================================================
1 michael 2011/09/08 新增
2 Michael 2025/07/11 改寫為MariaDB版本並優化
*/
BEGIN
DECLARE v_pos INT;
DECLARE v_cnt INT;
DECLARE v_length INT;
DECLARE v_temp TEXT;
DECLARE p_uuid VARCHAR(100);
DECLARE data TEXT;
SET v_length = LENGTH(p_split);
SET v_temp = p_source;
SET p_uuid = UUID();
SET v_cnt = 1;
-- 循環處理分割
WHILE LOCATE(p_split, v_temp) > 0 DO
SET v_pos = LOCATE(p_split, v_temp);
INSERT INTO _split (guid, rowid, col) VALUES (p_uuid, v_cnt, SUBSTRING(v_temp, 1, v_pos - 1));
SET v_temp = SUBSTRING(v_temp, v_pos + v_length);
SET v_cnt = v_cnt + 1;
END WHILE;
-- 添加最後一部分
IF LENGTH(v_temp) > 0 THEN
INSERT INTO _split(guid, rowid, col) VALUES (p_uuid, v_cnt, v_temp);
END IF;
SELECT JSON_ARRAYAGG(JSON_OBJECT('col', col)) INTO data
FROM
(
SELECT col FROM _split WHERE guid = p_uuid
) data;
-- del temp data
delete from _split WHERE guid = p_uuid;
RETURN data;
END //
DELIMITER ;
+54
View File
@@ -0,0 +1,54 @@
DELIMITER //
CREATE OR REPLACE PROCEDURE gp_split(
p_uuid VARCHAR(100),
p_source TEXT,
p_split VARCHAR(2)
)
/*
function : 將傳入的字串, 依 p_split 切割為多筆資料, 傳回暫存 table
description:
呼叫範例:
SET p_uuid = UUID();
CALL gp_split(p_uuid, 'R,G,B',',');
select col from _split where guid = p_uuid and rowid = 1;
DELETE FROM _split WHERE guid = p_uuid;
必須要有 CREATE TABLE _split( guid varchar(100), rowid INT, col varchar(600) );
https://www.sqlines.com/sql-server-to-mariadb/returns_table
build date : 2023/11/20
modify history
item who date modify docs
==== ========== ========== ================================================
1 michael 2011/09/08 新增
2 Michael 2025/07/11 改寫為MariaDB版本並優化
*/
BEGIN
DECLARE v_pos INT;
DECLARE v_cnt INT;
DECLARE v_length INT;
DECLARE v_temp TEXT;
SET v_length = LENGTH(p_split);
SET v_temp = p_source;
SET v_cnt = 1;
-- 循環處理分割
WHILE LOCATE(p_split, v_temp) > 0 DO
SET v_pos = LOCATE(p_split, v_temp);
INSERT INTO _split (guid, rowid, col) VALUES (p_uuid, v_cnt, SUBSTRING(v_temp, 1, v_pos - 1));
SET v_temp = SUBSTRING(v_temp, v_pos + v_length);
SET v_cnt = v_cnt + 1;
END WHILE;
-- 添加最後一部分
IF LENGTH(v_temp) > 0 THEN
INSERT INTO _split(guid, rowid, col) VALUES (p_uuid, v_cnt, v_temp);
END IF;
END //
DELIMITER ;
+345
View File
@@ -0,0 +1,345 @@
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 ;
+117
View File
@@ -0,0 +1,117 @@
DELIMITER //
CREATE OR REPLACE PROCEDURE orm_api_v2(
IN p_token VARCHAR(100), -- token(直接傳入)
IN p_tablename VARCHAR(200), -- tablename
IN p_pk VARCHAR(100), -- primary key(for update delete)
IN p_action VARCHAR(20), -- CRUDP(如果是 Read, p_paras 參數內容有特殊寫法)
IN p_paras LONGTEXT -- 前端組好的資料內容(應該是 json 格式的內容)
)
/*
Function : 寫一支通用 orm-api 依傳入的參數及設定, 智慧的組出相應的 sql
MariaDB 版本
Description: 本程式是想模仿 orm 的設定, 然後讓前端程式只要傳入參數, 就能執行 orm 的增刪查改的基本功能
R(Read) 是讀取單筆資料, p_paras 的參數內容同 CU >> 取消不用
P(Page) 是以頁為單位的讀取模式, 一般是 cowork with DataGrid
呼叫 api 範例如下
--新增資料
CALL orm_api_v2('B9F290D4-0F57-45B1-A786-F83A63E8BC4D','basarea','areaid','C','{"areaid":"mm", "areacnmae": "Michael"}');
CALL orm_api_v2('token_value','basarea','areaid','U','') --修改資料
CALL orm_api_v2('token_value','basarea','areaid','D','') --刪除資料
(pass)CALL orm_api_v2('B9F290D4-0F57-45B1-A786-F83A63E8BC4D','basarea','areaid','P','2^5^areaid^*'); -- 分頁查詢
-- 新增 Query 後要分頁顯示(擴充 P 的功能, 多傳 wheresql)
SET @para = CONCAT('areaid LIKE ',QUOTE('%A%'));
CALL orm_api_v2('token_value','basarea','areaid','P','1^10^fieldid^*^functiontag,tablename,fieldname^zen01');
-- 多筆資料 update
call orm_api_v2('aa54ef9b-7139-11f0-9c5f-d8bbc15c1404','bascustcategory','custcateid','U',
'{"rows":[
{"custcateid":"03","custcatecname":"大型企業","custcateename":"555","memochar":"","mergetype":"0"},
{"custcateid":"04","custcatecname":"政府","custcateename":"666","memochar":"","mergetype":"0"}],
"rowsDiff":[
{"custcateename":"555"},{"custcateename":"666"}],"indexes":["2","3"],
"rowsOrigin":[{"custcateid":"03","custcatecname":"大型企業","custcateename":"","memochar":"","mergetype":"0"},
{"custcateid":"04","custcatecname":"政府","custcateename":"","memochar":"","mergetype":"0"}],
"unModifiedItems":[
{"custcateid":"01","custcatecname":"經銷商","custcateename":"333","memochar":"","mergetype":"0"},
{"custcateid":"02","custcatecname":"代理商","custcateename":"444","memochar":"","mergetype":"0"},
{"custcateid":"05","custcatecname":"中小企業","custcateename":"","memochar":"","mergetype":"0"},
{"custcateid":"06","custcatecname":"學校","custcateename":"","memochar":"","mergetype":"0"},
{"custcateid":"07","custcatecname":"竹科","custcateename":"","memochar":"","mergetype":"0"}]
,"token":"aa54ef9b-7139-11f0-9c5f-d8bbc15c1404",
"_$_tableName":"bascustcategory",
"_$_pk":"custcateid","_$_action":"U"}');
SELECT * FROM orm_json_tmp;
delete FROM orm_json_tmp;
Build Date : 2023/12/16 (原始版本)
Modify Date: 2023/12/16 (MariaDB 遷移版本)
*/
BEGIN
DECLARE v_userid VARCHAR(100);
DECLARE v_uuid VARCHAR(36);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
-- 驗證 token
SELECT userid INTO v_userid FROM sys_users WHERE token = p_token LIMIT 1;
IF v_userid IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'token 錯誤, 請洽系統管理員!!';
END IF;
-- 整理 json 資料
SET p_paras = orm_retrive_json_v2(p_paras);
-- 刪除過期的暫存資料
DELETE FROM orm_json_tmp WHERE create_date < DATE_SUB(NOW(), INTERVAL 1 DAY);
-- 根據操作類型執行不同邏輯
IF p_action IN ('C', 'Insert', 'U', 'Update', 'D', 'Delete') THEN
-- 開啟事務
START TRANSACTION;
-- 處理 JSON 資料
SET p_paras = REPLACE(p_paras, '": "', '":"');
SET v_uuid = UUID();
-- call usp_parsejson(v_uuid,p_paras);
CALL parse_JSON(v_uuid, p_paras);
-- 將傳入的 json 寫入暫存表方便處理
INSERT INTO orm_json_tmp (uuid, parent_id, object_id, json_key, json_value, valuetype, create_date)
SELECT v_uuid, parent_id, object_id, name, stringvalue, ValueType, NOW()
FROM sys_jsondata WHERE UUID = v_uuid and valuetype <> 'OBJECT' and valuetype <> 'ARRAY';
-- 測試時先 Mark
DELETE FROM sys_jsondata WHERE UUID = v_uuid;
-- 根據操作類型調用不同副程式
IF p_action IN ('C', 'Insert') THEN
CALL orm_exec_insert_v2(p_tablename, p_pk, p_action, v_uuid, v_userid);
ELSEIF p_action IN ('U', 'Update') THEN
CALL orm_exec_update_v2(p_tablename, p_pk, p_action, v_uuid, v_userid);
ELSEIF p_action IN ('D', 'Delete') THEN
CALL orm_api_kernel_v2(p_tablename, p_pk, p_action, v_uuid, 1);
END IF;
-- 存檔後過帳機制
CALL orm_exec_aftersave_v2(p_tablename, p_pk, p_action, v_userid);
-- 提交事務
COMMIT;
ELSEIF p_action IN ('P', 'Page') THEN
-- 核心的 orm 程式, 取得顯示在 DataTable 的分頁資料
CALL orm_exec_page_v2(p_tablename, p_pk, v_userid, p_paras);
END IF;
END //
DELIMITER ;
+100
View File
@@ -0,0 +1,100 @@
DELIMITER //
CREATE OR REPLACE PROCEDURE orm_exec_aftersave_v2(
IN p_tablename VARCHAR(100),
IN p_pk VARCHAR(100), -- primary key(for update delete)
IN p_action VARCHAR(10),
IN p_userid VARCHAR(100)
)
/*
功能: orm_api_v2 [存档后处理]的核心程序,智能构建相应SQL
描述: 用于保存后执行额外处理逻辑
创建日期: 2023/12/16
MariaDB转换版本
*/
BEGIN
DECLARE v_sp_name TEXT;
DECLARE v_para01 TEXT;
DECLARE v_para02 TEXT;
DECLARE v_sql_command TEXT;
DECLARE v_dest_table TEXT;
DECLARE v_dest_field TEXT;
DECLARE v_dest_field2 TEXT;
DECLARE v_RelationKey TEXT;
DECLARE v_filter_user_fieldname TEXT;
DECLARE v_max_id INT;
-- 取得 sys_transaction 信息
SELECT
sp_name,
para01,
para02,
dest_table,
dest_field,
dest_field2,
RelationKey,
filter_user_fieldname
INTO
v_sp_name,
v_para01,
v_para02,
v_dest_table,
v_dest_field,
v_dest_field2,
v_RelationKey,
v_filter_user_fieldname
FROM sys_transaction
WHERE tablename = p_tablename AND (actiontype = '*' OR LOCATE(p_action, actiontype) > 0)
LIMIT 1;
IF v_sp_name IS NOT NULL AND v_sp_name != '' THEN
-- 检查是否为特殊情况
IF (v_sp_name != 'sys_transfer_owned2rolemenusecurity') AND (v_sp_name != 'sys_transfer_owned2userroles') THEN
-- 如果 pk 是 identity
IF v_para01 = 'identity' THEN
-- 处理 identity 的情况
IF IFNULL(v_filter_user_fieldname, '') = '' THEN
SET @sql = CONCAT('SELECT MAX(', p_pk, ') INTO @max_id FROM ', p_tablename);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET v_sql_command = CONCAT('UPDATE sys_transaction SET para01 = ? WHERE tablename = ''', p_tablename, '''');
PREPARE stmt FROM v_sql_command;
EXECUTE stmt USING @max_id;
DEALLOCATE PREPARE stmt;
ELSE
SET @sql = CONCAT('SELECT MAX(', p_pk, ') INTO @max_id FROM ', p_tablename,
' WHERE ', v_filter_user_fieldname, ' = ''', p_userid, '''');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET v_sql_command = CONCAT('UPDATE sys_transaction SET para01 = ? WHERE tablename = ''', p_tablename, '''');
PREPARE stmt FROM v_sql_command;
EXECUTE stmt USING @max_id;
DEALLOCATE PREPARE stmt;
END IF;
END IF;
SET v_sql_command = CONCAT('CALL ', v_sp_name, '( ''', p_tablename, ''' )');
ELSE
-- 针对特殊情况特别改写 sp 的方案
IF IFNULL(v_para01, '') != '' AND IFNULL(v_para02, '') != '' THEN
SET v_sql_command = CONCAT('CALL ', v_sp_name, '( ''', v_para01, ''', ''', v_para02, ''' )');
ELSEIF IFNULL(v_para01, '') != '' AND IFNULL(v_para02, '') = '' THEN
SET v_sql_command = CONCAT('CALL ', v_sp_name, '( ''', v_para01, ''' )');
ELSE
SET v_sql_command = CONCAT('CALL ', v_sp_name, '()');
END IF;
END IF;
-- 执行 SQL
SET @dynamic_sql = v_sql_command;
PREPARE stmt FROM @dynamic_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END //
DELIMITER ;
+179
View File
@@ -0,0 +1,179 @@
DELIMITER //
CREATE OR REPLACE PROCEDURE orm_exec_insert_v2(
IN p_tablename VARCHAR(200), -- tablename
IN p_pk VARCHAR(100), -- primary key(for update delete)
IN p_action VARCHAR(20), -- CRUDP
IN p_uuid VARCHAR(100),
IN p_userid VARCHAR(100)
)
/*
Function : orm_api_v2 [新增]的核心程式, 智慧的組出相應的 sql
Description: 關於 Master-Detail 的補充說明
Build Date : 2023/12/16
Modified for MariaDB
*/
BEGIN
DECLARE v_maxcount INT;
DECLARE v_currid INT;
DECLARE v_is_md SMALLINT;
DECLARE v_is_excel SMALLINT;
DECLARE v_maxid INT;
DECLARE v_excel_id INT;
DECLARE v_cnt INT;
DECLARE v_cn_field VARCHAR(100);
DECLARE v_cd_field VARCHAR(100);
DECLARE v_billno VARCHAR(20);
DECLARE v_sub_table VARCHAR(100);
DECLARE v_sql TEXT;
DECLARE v_max_no VARCHAR(20);
DECLARE v_maxcnt INT;
-- step 1: 判斷狀態: 是否 master-detail 多筆資料?
SELECT MAX(parent_id) INTO v_maxcount FROM orm_json_tmp WHERE uuid = p_uuid;
-- @is_md 是使用 input-table template 用的判斷
SELECT COUNT(*), IFNULL(MAX(parent_id), 0)
INTO v_is_md, v_maxid
FROM orm_json_tmp
WHERE uuid = p_uuid AND json_key = 'details' AND valuetype = 'array';
SELECT COUNT(*), IFNULL(MAX(parent_id), 0)
INTO v_is_excel, v_excel_id
FROM orm_json_tmp
WHERE uuid = p_uuid AND json_key = 'excel' AND valuetype = 'array';
-- step 2: update/insert create_user (僅允許一次一筆資料)
SET v_cn_field = 'create_user';
SET v_cd_field = 'create_date';
-- Check if create_user column exists
SELECT COUNT(*) INTO v_cnt
FROM information_schema.columns
WHERE table_name = p_tablename AND column_name = v_cn_field;
IF v_cnt > 0 THEN
SELECT COUNT(*) INTO v_cnt FROM orm_json_tmp WHERE uuid = p_uuid AND json_key = v_cn_field;
IF v_cnt = 0 THEN
INSERT INTO orm_json_tmp (uuid, parent_id, json_key, json_value, ValueType)
VALUES (p_uuid, v_maxcount, v_cn_field, p_userid, 'string');
ELSE
UPDATE orm_json_tmp SET json_value = p_userid
WHERE uuid = p_uuid AND json_key = v_cn_field;
END IF;
END IF;
-- Check if create_date column exists
SELECT COUNT(*) INTO v_cnt
FROM information_schema.columns
WHERE table_name = p_tablename AND column_name = v_cd_field;
IF v_cnt > 0 THEN
SELECT COUNT(*) INTO v_cnt FROM orm_json_tmp WHERE uuid = p_uuid AND json_key = v_cd_field;
IF v_cnt = 0 THEN
INSERT INTO orm_json_tmp (uuid, parent_id, json_key, json_value, ValueType)
VALUES (p_uuid, v_maxcount, v_cd_field, DATE_FORMAT(NOW(), '%Y-%m-%d'), 'string');
ELSE
UPDATE orm_json_tmp SET json_value = DATE_FORMAT(NOW(), '%Y-%m-%d')
WHERE uuid = p_uuid AND json_key = v_cd_field;
END IF;
END IF;
-- step 3: 針對 m-d 的單號前置處理(針對 billno=自動編碼, 給定新的單號)
SELECT COUNT(*) INTO v_cnt
FROM orm_json_tmp
WHERE uuid = p_uuid AND json_key = 'billno'
AND (json_value LIKE '%自動%' OR json_value LIKE '%Auto%');
IF v_cnt > 0 THEN
-- hard-code
IF p_pk = '' OR p_tablename LIKE '%_d%' THEN
-- master-detail 的 detail insert
SET v_max_no = CONCAT(SUBSTRING(p_tablename, 4, 6), SUBSTRING(p_userid, 1, 6));
ELSE
-- 先取得今天最大號
SET @sql = CONCAT('SELECT MAX(billno) INTO @max_billno FROM ', p_tablename,
' WHERE DATE(billdate) = CURDATE()');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 計算新單號 (需要實現 sys_next_no 函數)
SET v_max_no = sys_next_no(@max_billno);
-- 紀錄新增單號
DELETE FROM sys_new_billno WHERE create_time < DATE_SUB(NOW(), INTERVAL 3 DAY);
-- 防錯
SELECT COUNT(*) INTO v_maxcnt
FROM sys_new_billno
WHERE tablename = p_tablename AND login_user = p_userid;
IF v_maxcnt > 0 THEN
UPDATE sys_new_billno SET billno = v_max_no
WHERE tablename = p_tablename AND login_user = p_userid;
ELSE
INSERT INTO sys_new_billno VALUES (p_tablename, p_userid, v_max_no, NOW());
END IF;
END IF;
UPDATE orm_json_tmp SET json_value = v_max_no
WHERE uuid = p_uuid AND json_key = 'billno'
AND (json_value LIKE '%自動%' OR json_value LIKE '%Auto%');
END IF;
-- master-detail
IF v_is_md > 0 THEN
-- 寫入 master 一筆
CALL orm_api_kernel_v2(p_tablename, p_pk, p_action, p_uuid, v_maxcount);
-- 取得表頭的單號
SELECT billno INTO v_billno
FROM sys_new_billno
WHERE tablename = p_tablename AND login_user = p_userid;
-- 寫入 details 多筆
SELECT detail_table INTO v_sub_table
FROM zen_function
WHERE maintable = p_tablename
LIMIT 1;
IF IFNULL(v_sub_table, '') = '' THEN
SET v_sub_table = CONCAT(SUBSTRING(p_tablename, 1, LENGTH(p_tablename)-1), 'd');
END IF;
-- 多筆 detail 資料寫入
SET v_currid = 1;
WHILE v_currid < v_maxid DO
-- 執行核心程式
CALL orm_api_kernel_v2(v_sub_table, p_pk, p_action, p_uuid, v_currid);
-- 取得下一筆資料
SET v_currid = v_currid + 1;
END WHILE;
ELSEIF v_is_excel > 0 THEN
-- excel 多筆資料匯入
SET v_currid = 1;
WHILE v_currid < v_excel_id-1 DO
-- 執行核心程式
CALL orm_api_kernel_v2(p_tablename, p_pk, p_action, p_uuid, v_currid);
-- 取得下一筆資料
SET v_currid = v_currid + 1;
END WHILE;
ELSEIF v_maxcount > 1 THEN
-- 多筆資料寫入
SET v_currid = 1;
WHILE v_currid <= v_maxcount DO
-- 執行核心程式
CALL orm_api_kernel_v2(p_tablename, p_pk, p_action, p_uuid, v_currid);
-- 取得下一筆資料
SET v_currid = v_currid + 1;
END WHILE;
ELSE
CALL orm_api_kernel_v2(p_tablename, p_pk, p_action, p_uuid, 1);
END IF;
END //
DELIMITER ;
+181
View File
@@ -0,0 +1,181 @@
DELIMITER $$
CREATE OR REPLACE PROCEDURE orm_exec_page_v2 (
IN _tablename VARCHAR(200),
IN _pk VARCHAR(100),
IN _userid VARCHAR(100),
IN _paras TEXT
)
/*
Function : orm_api_v2 [分頁查詢]的核心程式, 智慧的組出相應的 sql, 被 orm_api_v2 呼叫使用
Description: 要特別注意傳入的參數正確性, 下面是一個正確的 case
call orm_api_v2('b013a91a-daf1-11f0-a07a-d8bbc15c1404','basperson','personid','P','1^100^personid^*^^^personcname^林^^');
Build Date : 2025/07/11
Modify History
Item Who Date Modify Docs
==== ========== ========== ================================================
1 Michael 2025/07/11 根據 ms-sql 的版本, 利用 ChatGPT/DeepSeek 等AI, 改寫為 Mariadb 版
*/
BEGIN
DECLARE _pageno INT DEFAULT 1;
DECLARE _pagerec INT DEFAULT 10;
DECLARE _orderby TEXT DEFAULT '';
DECLARE _udf_fields TEXT DEFAULT '*';
DECLARE _wheresql TEXT DEFAULT '';
DECLARE _wheresql_org TEXT DEFAULT '';
DECLARE _where_value TEXT DEFAULT '';
DECLARE _where_fields TEXT DEFAULT '';
DECLARE _where_field TEXT DEFAULT '';
DECLARE _where_idvalue TEXT DEFAULT '';
DECLARE _menuid TEXT DEFAULT '';
DECLARE _jointables TEXT DEFAULT '';
DECLARE _joinfields TEXT DEFAULT '';
DECLARE _tbl_alias TEXT DEFAULT '';
DECLARE _alias TEXT DEFAULT '';
DECLARE _startrec INT DEFAULT 0;
DECLARE _sql TEXT;
DECLARE _sql_cnt TEXT;
DECLARE _dtc INT DEFAULT 0;
DECLARE _guid VARCHAR(100);
--
DECLARE v_field VARCHAR(200);
DECLARE v_pos INT DEFAULT 1;
DECLARE v_count INT;
-- 錯誤處理
/*
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
SELECT '9999' AS code, '資料庫操作錯誤' AS msg;
END;
*/
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
@sqlstate = RETURNED_SQLSTATE,
@errno = MYSQL_ERRNO,
@text = MESSAGE_TEXT;
SELECT 1 AS code, CONCAT('Error: ', @errno, ' (', @sqlstate, '): ', @text) AS msg;
END;
SET _guid = UUID();
CALL gp_split(_guid, _paras, '^');
-- 使用 split 暫存表方式處理參數
SELECT col INTO _pageno FROM _split WHERE guid = _guid and rowid = 1;
SELECT col INTO _pagerec FROM _split WHERE guid = _guid and rowid = 2;
SELECT col INTO _orderby FROM _split WHERE guid = _guid and rowid = 3;
SELECT col INTO _udf_fields FROM _split WHERE guid = _guid and rowid = 4;
SELECT col INTO _wheresql_org FROM _split WHERE guid = _guid and rowid = 5;
SELECT col INTO _menuid FROM _split WHERE guid = _guid and rowid = 6;
SELECT col INTO _where_fields FROM _split WHERE guid = _guid and rowid = 7;
SELECT col INTO _where_value FROM _split WHERE guid = _guid and rowid = 8;
SELECT col INTO _where_field FROM _split WHERE guid = _guid and rowid = 9;
SELECT col INTO _where_idvalue FROM _split WHERE guid = _guid and rowid = 10;
DELETE FROM _split WHERE guid = _guid;
-- 預設排序欄位
IF _orderby IS NULL OR _orderby = '' THEN SET _orderby = _pk; END IF;
IF _udf_fields IS NULL OR _udf_fields = '' THEN SET _udf_fields = '*'; END IF;
-- 防錯
SET _jointables = '';
IF _menuid IS NOT NULL AND _menuid <> '' THEN
SELECT joinfields, jointables INTO _joinfields, _jointables
FROM sys_joinfields WHERE menuid = _menuid;
SET _alias = 'ma.';
SET _tbl_alias = ' ma ';
IF LOCATE('ma.', _orderby) = 0 THEN
SET _orderby = CONCAT(_alias, _orderby);
END IF;
END IF;
-- 建立 WHERE 條件
IF _where_value IS NOT NULL AND _where_value <> '' THEN
IF LOCATE(',', _where_fields) > 0 THEN
-- SET _wheresql = REPLACE(_where_fields, ',', CONCAT(' LIKE ',"'",'%', _where_value, '%', "'", ' OR ', _alias));
-- SET _wheresql = CONCAT(' WHERE (', _alias, _where_fields, ' LIKE ', QUOTE(CONCAT('%', _where_value, '%')), ')');
-- 改寫, 本段程式目的是要多欄位 like 查詢
SET v_count = LENGTH(_where_fields) - LENGTH(REPLACE(_where_fields, ',', '')) + 1;
WHILE v_pos <= v_count DO
SET v_field = TRIM(
SUBSTRING_INDEX(
SUBSTRING_INDEX(_where_fields, ',', v_pos),
',', -1
)
);
SET _wheresql = CONCAT(
_wheresql,
IF(v_pos > 1, ' OR ', ''),
v_field,
' LIKE ',
QUOTE(CONCAT('%', _where_value, '%'))
);
SET v_pos = v_pos + 1;
END WHILE;
SET _wheresql = CONCAT(' WHERE (', _wheresql, ')');
--
ELSE
SET _wheresql = CONCAT(' WHERE ', _alias, _where_fields, ' LIKE ', QUOTE(CONCAT('%', _where_value, '%')));
END IF;
END IF;
-- debug
-- select concat('where9: ',_wheresql);
-- 加入網址參數條件
IF _where_idvalue IS NOT NULL AND _where_idvalue <> '' THEN
IF _wheresql = '' THEN
SET _wheresql = CONCAT(' WHERE ', _alias, _where_field, ' = ', QUOTE(_where_idvalue));
ELSE
SET _wheresql = CONCAT(_wheresql, ' AND ', _alias, _where_field, ' = ', QUOTE(_where_idvalue));
END IF;
END IF;
-- 加上前端傳入的原始 WHERE
IF _wheresql_org IS NOT NULL AND _wheresql_org <> '' THEN
SET _wheresql_org = REPLACE(_wheresql_org, '~', "'");
IF _wheresql = '' THEN
SET _wheresql = CONCAT(' WHERE ', _wheresql_org);
ELSE
SET _wheresql = CONCAT(_wheresql, ' AND ', _wheresql_org);
END IF;
END IF;
-- 計算 offset
SET _startrec = (_pageno - 1) * _pagerec;
-- 查詢筆數
SET _sql_cnt = CONCAT('SELECT COUNT(*) INTO @dtc FROM ', _tablename, _tbl_alias, ' ', _wheresql);
PREPARE stmt_cnt FROM _sql_cnt;
EXECUTE stmt_cnt;
DEALLOCATE PREPARE stmt_cnt;
SELECT 0 AS code, 'ok' AS msg, @dtc AS recno;
-- SELECT 'debug' AS code, _sql_cnt AS msg, @dtc AS recno;
-- 組合查詢 SQL
IF _jointables IS NULL OR _jointables = '' THEN
SET _sql = CONCAT('SELECT ', _udf_fields, ' FROM ', _tablename, _tbl_alias, ' ', _wheresql,
' ORDER BY ', _orderby, ' LIMIT ', _pagerec, ' OFFSET ', _startrec);
ELSE
SET _sql = CONCAT('SELECT ', _joinfields, ' FROM ', _tablename, _tbl_alias, _jointables, ' ',
_wheresql, ' ORDER BY ', _orderby, ' LIMIT ', _pagerec, ' OFFSET ', _startrec);
END IF;
-- 執行查詢
PREPARE stmt FROM _sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
+99
View File
@@ -0,0 +1,99 @@
DELIMITER //
CREATE OR REPLACE PROCEDURE orm_exec_update_v2(
IN p_tablename VARCHAR(200), -- 表名
IN p_pk VARCHAR(100), -- 主键(用于更新/删除)
IN p_action VARCHAR(20), -- CRUDP操作
IN p_uuid VARCHAR(100), -- UUID标识
IN p_userid VARCHAR(100) -- 用户ID
)
/*
功能: orm_api_v2 [更新]的核心程序,智能构建相应SQL
描述: 用于更新操作的ORM核心逻辑
创建日期: 2023/12/16
MariaDB转换版本
*/
BEGIN
DECLARE v_maxcount, v_rec INT;
DECLARE v_currid INT;
DECLARE v_cnt INT;
DECLARE v_un_field VARCHAR(100);
DECLARE v_ud_field VARCHAR(100);
-- 步骤1: 获取最小parent_id (rows)
SELECT MIN(parent_id) INTO v_maxcount
FROM orm_json_tmp
WHERE uuid = p_uuid; -- AND valuetype in ('ARRAY','object');
-- 取得欲更新筆數
SELECT MAX(object_id) INTO v_rec
FROM orm_json_tmp
WHERE uuid = p_uuid AND parent_id = v_maxcount;
-- 步骤2: 更新/插入update_user和update_date字段
SET v_un_field = 'update_user';
SET v_ud_field = 'update_date';
-- 检查update_user字段是否存在
SELECT COUNT(*) INTO v_cnt
FROM information_schema.columns
WHERE table_name = p_tablename AND column_name = v_un_field;
IF v_cnt > 0 THEN
SELECT COUNT(*) INTO v_cnt
FROM orm_json_tmp
WHERE uuid = p_uuid AND json_key = v_un_field;
IF v_cnt = 0 THEN
INSERT INTO orm_json_tmp (uuid, parent_id, json_key, json_value, ValueType)
VALUES (p_uuid, v_maxcount, v_un_field, p_userid, 'string');
ELSE
UPDATE orm_json_tmp
SET json_value = p_userid
WHERE uuid = p_uuid AND json_key = v_un_field;
END IF;
END IF;
-- 检查update_date字段是否存在
SELECT COUNT(*) INTO v_cnt
FROM information_schema.columns
WHERE table_name = p_tablename AND column_name = v_ud_field;
IF v_cnt > 0 THEN
SELECT COUNT(*) INTO v_cnt
FROM orm_json_tmp
WHERE uuid = p_uuid AND json_key = v_ud_field;
IF v_cnt = 0 THEN
INSERT INTO orm_json_tmp (uuid, parent_id, json_key, json_value, ValueType)
VALUES (p_uuid, v_maxcount, v_ud_field, DATE_FORMAT(NOW(), '%Y-%m-%d'), 'string');
ELSE
UPDATE orm_json_tmp
SET json_value = DATE_FORMAT(NOW(), '%Y-%m-%d')
WHERE uuid = p_uuid AND json_key = v_ud_field;
END IF;
END IF;
-- 日期欄位要格式化處理(待驗證)
UPDATE orm_json_tmp
SET json_value = DATE_FORMAT(substr(json_value,1,10), '%Y-%m-%d')
WHERE uuid = p_uuid AND json_key in (select column_name from information_schema.columns WHERE table_name = p_tablename and substr(data_type,1,4) = 'date')
and json_value is not null;
-- 判断是否有多笔资料
IF v_rec > 1 THEN -- v_maxcount
SET v_currid = 1;
WHILE v_currid <= v_rec DO
-- 执行核心程序
CALL orm_api_kernel_v2(p_tablename, p_pk, p_action, p_uuid, v_maxcount*1000 + v_currid);
-- 取得下一笔资料
SET v_currid = v_currid + 1;
END WHILE;
ELSE
-- 單筆資料傳入
CALL orm_api_kernel_v2(p_tablename, p_pk, p_action, p_uuid, 1);
END IF;
END //
DELIMITER ;
+131
View File
@@ -0,0 +1,131 @@
DELIMITER //
DROP FUNCTION IF EXISTS orm_page_where_v2;
CREATE FUNCTION orm_page_where_v2(
tablename VARCHAR(200), -- 表名
pk VARCHAR(100), -- 主键(用于更新删除)
where_sql TEXT, -- 原始 WHERE 条件
userid VARCHAR(100) -- 用户ID
)
RETURNS TEXT
DETERMINISTIC
/*
Function : orm_api_v2 [分頁查詢] where 條件判斷的核心程式, 智慧的組出相應的 sql, 被 orm_api_page_v2 呼叫使用
Description:
Build Date : 2024-06-20
Modify History:
1 Michael 2023/12/16 原始版本
2 [优化版] 2024-06-20 MariaDB优化版本
*/
BEGIN
DECLARE wheresql TEXT;
DECLARE limit_s_date VARCHAR(100);
DECLARE limit_e_date VARCHAR(100);
DECLARE limit_field VARCHAR(100);
DECLARE limit_field_d VARCHAR(100);
DECLARE limit_filter_master TEXT;
DECLARE limit_table_d VARCHAR(1000);
DECLARE limit_filter_detail TEXT;
DECLARE limit_filter_date VARCHAR(200);
DECLARE maxcount INT DEFAULT 0;
DECLARE new_billno VARCHAR(100);
DECLARE comma_pos INT;
DECLARE emp1, emp2, emp3 VARCHAR(200);
-- 初始化 WHERE 子句
SET wheresql = IF(where_sql = '', ' WHERE 1=1 ', where_sql);
-- 获取高级查询限制配置
SELECT
limit_field, limit_table_d, limit_field_d, limit_s_date, limit_e_date
INTO
limit_field, limit_table_d, limit_field_d, limit_s_date, limit_e_date
FROM sys_menutable
WHERE limit_table = tablename
AND islimitdata = 'Y'
LIMIT 1;
-- 如果存在限制字段且用户已登录
IF limit_field IS NOT NULL AND userid <> '' THEN
-- 检查是否有全局权限 (*)
SELECT COUNT(*) INTO maxcount
FROM basperson_share
WHERE personid = userid
AND share_personid = '*';
-- 如果没有全局权限,则添加个人限制条件
IF maxcount = 0 THEN
-- 初始化过滤条件
SET limit_filter_master = '';
SET limit_filter_detail = '';
SET limit_filter_date = '';
-- 添加日期范围限制
IF limit_s_date <> '' AND limit_e_date <> '' THEN
SET limit_filter_date = CONCAT(
' AND ', limit_s_date, ' <= CURDATE()',
' AND ', limit_e_date, ' >= CURDATE()'
);
END IF;
-- 添加明细表限制
IF limit_field_d <> '' THEN
SET limit_filter_detail = CONCAT(
' OR ', pk, ' IN (',
'SELECT ', pk, ' FROM ', limit_table_d,
' WHERE ', limit_field_d, ' = ', QUOTE(userid),
limit_filter_date, ')'
);
END IF;
-- 处理多字段限制
SET comma_pos = LOCATE(',', limit_field);
IF comma_pos > 0 THEN
-- 拆分字段列表
SET emp1 = SUBSTRING_INDEX(limit_field, ',', 1);
SET emp2 = SUBSTRING_INDEX(SUBSTRING_INDEX(limit_field, ',', 2), ',', -1);
SET emp3 = IF(LOCATE(',', limit_field, LENGTH(emp1) + LENGTH(emp2) + 3) > 0,
SUBSTRING_INDEX(limit_field, ',', -1),
NULL);
-- 构建多字段限制条件
SET wheresql = CONCAT(wheresql, ' AND (');
SET wheresql = CONCAT(wheresql, emp1, ' IN (SELECT share_personid FROM basperson_share WHERE personid = ', QUOTE(userid), ')');
IF emp2 <> '' THEN
SET wheresql = CONCAT(wheresql, ' OR ', emp2, ' IN (SELECT share_personid FROM basperson_share WHERE personid = ', QUOTE(userid), ')');
END IF;
IF emp3 IS NOT NULL THEN
SET wheresql = CONCAT(wheresql, ' OR ', emp3, ' IN (SELECT share_personid FROM basperson_share WHERE personid = ', QUOTE(userid), ')');
END IF;
SET wheresql = CONCAT(wheresql, limit_filter_date, ')', limit_filter_detail);
ELSE
-- 单字段限制条件
SET limit_filter_master = CONCAT(
' AND ', limit_field, ' IN (',
'SELECT share_personid FROM basperson_share WHERE personid = ', QUOTE(userid), ')',
limit_filter_date
);
SET wheresql = CONCAT(wheresql, limit_filter_master, limit_filter_detail);
END IF;
END IF;
END IF;
/* 新增记录后只显示刚添加的数据 */
SELECT billno INTO new_billno
FROM sys_new_billno
WHERE tablename = tablename
AND login_user = userid
AND create_time >= NOW() - INTERVAL 30 SECOND
LIMIT 1;
IF new_billno IS NOT NULL THEN
SET wheresql = CONCAT(wheresql, ' AND billno = ', QUOTE(new_billno));
END IF;
RETURN wheresql;
END //
DELIMITER ;
+64
View File
@@ -0,0 +1,64 @@
DELIMITER //
CREATE OR REPLACE FUNCTION orm_retrive_json_v2(
paras TEXT
)
RETURNS TEXT
DETERMINISTIC
/*
Function : orm_api_v2 [傳入 json 的資料預處理] 的核心程式, 被 orm_api_v2 呼叫使用
Description: 刪除 @para 多餘的內容(amis)
如果有特殊元件(如 transfer) 會多 POST 非 orm 所需的資料, 一樣要拿掉
picker 如果有設 joinValues:false, 也會多傳一些多餘的資料
Build Date : 2024-06-20
Modify History:
1 Michael 2023/12/16 原始版本
2 Michael 2024-06-20 改寫為MariaDB版本並優化
*/
BEGIN
DECLARE result TEXT;
DECLARE maxcount INT;
DECLARE currid INT;
DECLARE trans_data TEXT;
DECLARE json_valid BOOLEAN;
-- 檢查是否為有效JSON,如果是則直接處理,否則按原邏輯處理
SET json_valid = JSON_VALID(paras);
-- 進行一些操作,根據需求修改下面的程式碼
SET result = paras;
-- 處理 config 部分
SET maxcount = INSTR(result, '"config":[');
IF maxcount > 0 THEN
-- 在 config 後可能還有資料
SET trans_data = SUBSTRING(result FROM maxcount);
SET currid = INSTR(trans_data, '],');
SET trans_data = SUBSTRING(trans_data FROM currid + 2);
SET result = CONCAT(SUBSTRING(result FROM 1 FOR maxcount - 1), ' ', trans_data);
END IF;
-- 處理 token 部分(除非是電子書情況)
SET maxcount = INSTR(result, '"token"');
IF maxcount > 0 THEN
SET result = CONCAT(SUBSTRING(result FROM 1 FOR maxcount - 2), '}');
END IF;
-- 處理換行符
IF INSTR(result, '\\n') > 0 THEN
SET result = REPLACE(REPLACE(result, '\\r\\n', CHAR(10)), '\\n', CHAR(10));
END IF;
-- 如果是有效JSON,最後再驗證一次
IF json_valid THEN
IF NOT JSON_VALID(result) THEN
-- 如果處理後變無效,返回原始值
RETURN paras;
END IF;
END IF;
RETURN result;
END //
DELIMITER ;
+168
View File
@@ -0,0 +1,168 @@
DELIMITER //
CREATE OR REPLACE PROCEDURE Parse_JSON(
IN p_uuid VARCHAR(100),
IN json_input JSON
)
/*
call Parse_JSON('uuid-20250803',
'{"custcateid":"08","custcatecname":"8888","custcateename":"","memochar":"","mergetype":"","token":"c975931c-6f8d-11f0-9c5f-d8bbc15c1404","_$_tableName":"bascustcategory",
"_$_pk":"custcateid",
"_$_action":"D"}');
call Parse_JSON('uuid-20250803',
'{"sprintid":"Next-Sprint","sprint_title":"調整現行 PBI 緩衝用的 Sprint(2025)","sprint_startdate":"2025-01-01T00:00:00.000+08:00","sprint_enddate":"2099-12-30T16:00:00.000Z","time_range":"2099",
"token":"768f1c89-6fb9-11f0-9c5f-d8bbc15c1404",
"_$_tableName":"pms_sprint",
"_$_pk":"sprintid",
"_$_action":"U"}');
call Parse_JSON('uuid-20250803_3',
'{"rows":[{"custcateid":"09","custcatecname":"9999","custcateename":"9999-memo","memochar":"","mergetype":""}],
"rowsDiff":[{"custcateename":"9999-memo"}],"indexes":["7"],
"rowsOrigin":
[{"custcateid":"09","custcatecname":"9999","custcateename":"","memochar":"","mergetype":""}],
"unModifiedItems":[
{"custcateid":"01","custcatecname":"經銷商","custcateename":"333","memochar":"","mergetype":"0"},
{"custcateid":"02","custcatecname":"代理商","custcateename":"444","memochar":"","mergetype":"0"},
{"custcateid":"03","custcatecname":"大型企業","custcateename":"","memochar":"","mergetype":"0"},
{"custcateid":"04","custcatecname":"政府","custcateename":"","memochar":"","mergetype":"0"},
{"custcateid":"05","custcatecname":"中小企業","custcateename":"","memochar":"","mergetype":"0"},
{"custcateid":"06","custcatecname":"學校","custcateename":"","memochar":"","mergetype":"0"},
{"custcateid":"07","custcatecname":"竹科","custcateename":"","memochar":"","mergetype":"0"}],
"token":"d101363e-700c-11f0-9c5f-d8bbc15c1404","_$_tableName":"bascustcategory","_$_pk":"custcateid","_$_action":"U"}');
call Parse_JSON('uuid-20250820_1',
'{"projectclassid":"soft-dev","proj_boss":"120102",
"config":[{"label":"(GM) 總經理室",
"children":[
{"label":"(120101) 高光","value":"120101"},
{"label":"(121108) 沈秋月","value":"121108"},
{"label":"(200605) 陳明文","value":"200605"},
{"label":"(120102) 王俊傑","value":"120102"},
{"label":"(150201) 衛斯理","value":"150201"},
{"label":"(190802) 葉子龍","value":"190802"},
{"label":"(210301) 高國華","value":"210301"},
{"label":"(admin)admin","value":"admin"},
{"label":"(160805) 邱雅惠","value":"160805"},
{"label":"(170911) 劉強南","value":"170911"},
{"label":"(201001) 林志堅","value":"201001"},
{"label":"(120912) 陳進德","value":"120912"},
{"label":"(170109) 林玉玲","value":"170109"},
{"label":"(180210) 秦一明","value":"180210"},
{"label":"(191006) 歐陽龍","value":"191006"},
{"label":"(201036) 邱郁芳","value":"201036"},
{"label":"(demo) 測試用戶","value":"demo"}]
}],
"projectid":"IT-2025-Chaos","proj_cname":"MariaDB改寫專案","proj_status":"SASD","proj_startdate":"2025-08-01","proj_enddate":"2025-09-30",
"proj_year":"2025","token":"a85afca2-7dc5-11f0-9c5f-d8bbc15c1404",
"_$_tableName":"pmsproject",
"_$_pk":"projectid",
"_$_action":"C"}');
*/
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE total_keys INT;
DECLARE key_name VARCHAR(255);
DECLARE val JSON;
DECLARE sub_key_name VARCHAR(255);
DECLARE sub_val JSON;
DECLARE sub_total_keys INT;
DECLARE j INT;
DECLARE x INT;
DECLARE y INT;
DECLARE arr_count,arr_idx INT;
DECLARE arr_obj JSON;
-- 取第一層 keys 數量
SET total_keys = JSON_LENGTH(JSON_KEYS(json_input));
SET x = 1;
SET y = 1;
WHILE i < total_keys DO
SET key_name = JSON_UNQUOTE(JSON_EXTRACT(JSON_KEYS(json_input), CONCAT('$[', i, ']')));
SET val = JSON_EXTRACT(json_input, CONCAT('$.', key_name));
-- 插入第一層
-- INSERT INTO tmp_json_parse_result (level, parent_key, key_name, value)
INSERT INTO sys_jsondata (UUID, `NAME`, SequenceNo, parent_ID, StringValue, ValueType)
VALUES (p_uuid, key_name, x, NULL, JSON_UNQUOTE(val), JSON_TYPE(val));
SET y = x;
SET x = x + 1;
-- 第二層處理:若 value 是 object 或 array,解析其 key-value (當前版本只處理 2層, 多的暫時不管)
IF JSON_TYPE(val) IN ('OBJECT', 'ARRAY') THEN
-- 先處理 ARRAY 可能有多筆資料
IF JSON_TYPE(val) = 'ARRAY' THEN
SET arr_count = JSON_LENGTH(val);
SET arr_idx = 0;
WHILE arr_idx < arr_count DO
-- 取出陣列中的單一物件
SET arr_obj = JSON_EXTRACT(val, CONCAT('$[', arr_idx, ']'));
SET j = 0;
SET sub_total_keys = JSON_LENGTH(JSON_KEYS(arr_obj));
WHILE j < sub_total_keys DO
SET sub_key_name = JSON_UNQUOTE(JSON_EXTRACT(JSON_KEYS(arr_obj), CONCAT('$[', j, ']')));
SET sub_val = JSON_EXTRACT(arr_obj, CONCAT('$.', sub_key_name));
INSERT INTO sys_jsondata (UUID, `NAME`, SequenceNo, parent_ID, Object_ID, StringValue, ValueType)
VALUES (p_uuid, sub_key_name, x, y, arr_idx+1, JSON_UNQUOTE(sub_val), JSON_TYPE(sub_val));
SET j = j + 1;
SET x = x + 1;
END WHILE;
SET arr_idx = arr_idx + 1;
END WHILE;
ELSE
-- 處理單一 OBJECT
SET j = 0;
SET sub_total_keys = JSON_LENGTH(JSON_KEYS(val));
WHILE j < sub_total_keys DO
SET sub_key_name = JSON_UNQUOTE(JSON_EXTRACT(JSON_KEYS(val), CONCAT('$[', j, ']')));
SET sub_val = JSON_EXTRACT(val, CONCAT('$.', sub_key_name));
INSERT INTO sys_jsondata (UUID, `NAME`, SequenceNo, parent_ID, StringValue, ValueType)
VALUES (p_uuid, sub_key_name, x, y, JSON_UNQUOTE(sub_val), JSON_TYPE(sub_val));
SET j = j + 1;
SET x = x + 1;
END WHILE;
END IF;
END IF;
/*
-- 第二層處理:若 value 是 object,解析其 key-value
IF JSON_TYPE(val) in ('OBJECT','ARRAY') THEN
-- 先解決 rows Grid Edit 多筆資料, 後續應該還有其他狀況要一一排除
SET j = 0;
-- IF SELECT TRIM(BOTH '[]' FROM '[example]') AS result;
SET sub_total_keys = JSON_LENGTH(JSON_KEYS(val));
WHILE j < sub_total_keys DO
SET sub_key_name = JSON_UNQUOTE(JSON_EXTRACT(JSON_KEYS(val), CONCAT('$[', j, ']')));
SET sub_val = JSON_EXTRACT(val, CONCAT('$.', sub_key_name));
-- INSERT INTO tmp_json_parse_result (level, parent_key, key_name, value)
INSERT INTO sys_jsondata (UUID, `NAME`, SequenceNo, parent_ID, StringValue, ValueType)
VALUES (p_uuid, sub_key_name, x, y , JSON_UNQUOTE(sub_val), JSON_TYPE(val));
SET j = j + 1;
SET x = x + 1;
END WHILE;
END IF;
*/
SET i = i + 1;
END WHILE;
END //
DELIMITER ;
+70
View File
@@ -0,0 +1,70 @@
DELIMITER $$
CREATE OR REPLACE PROCEDURE usp_parsejson (
IN _uuid VARCHAR(100),
IN _json TEXT
)
/*
CALL usp_parsejson('1234', '{ "id":"abc", "nmae": "Michael"}');
SELECT * from _jsondata WHERE guid = '1234';
DELETE FROM _jsondata WHERE guid = '1234';
*/
BEGIN
DECLARE _json_clean TEXT;
DECLARE _pair TEXT;
DECLARE _key VARCHAR(255);
DECLARE _value TEXT;
DECLARE _valuetype VARCHAR(20);
DECLARE _pos INT DEFAULT 1;
DECLARE _len INT;
DECLARE _curr INT DEFAULT 1;
DECLARE _next INT;
DECLARE _cnt INT DEFAULT 1;
-- 建立暫存表
CREATE TEMPORARY TABLE IF NOT EXISTS _jsondata (
guid VARCHAR(100),
rowid INT,
fieldname VARCHAR(255),
contents TEXT,
fieldtype VARCHAR(20)
);
-- 清除左右大括號與空白
SET _json_clean = REPLACE(_json,'{','');
SET _json_clean = REPLACE(_json_clean,'}','');
-- 計算逗號數(也就是 key:value 數)
SET _len = LENGTH(_json_clean) - LENGTH(REPLACE(_json_clean, ',', '')) + 1;
WHILE _cnt <= _len DO
-- 取出第 cnt 個 key:value 配對
SET _pair = SUBSTRING_INDEX(SUBSTRING_INDEX(_json_clean, ',', _cnt), ',', -1);
-- 取出 key
SET _key = SUBSTRING_INDEX(_pair, ':', 1);
SET _key = REPLACE(TRIM(_key),'"','');
-- 取出 value
SET _value = SUBSTRING_INDEX(_pair, ':', -1);
SET _value = TRIM(_value);
-- 判斷型別
IF LEFT(_value, 1) = '"' AND RIGHT(_value, 1) = '"' THEN
SET _valuetype = 'string';
SET _value = REPLACE(_value,'"','');
ELSE
SET _valuetype = 'number';
END IF;
-- 寫入結果
INSERT INTO _jsondata (guid, rowid, fieldname, contents, fieldtype)
VALUES (_uuid, _cnt, _key, _value, _valuetype);
-- 下一筆
SET _cnt = _cnt + 1;
END WHILE;
END$$
DELIMITER ;