DELIMITER // CREATE OR REPLACE PROCEDURE `zen_create_table` ( IN p_tablename VARCHAR(100), IN p_source_type VARCHAR(1) -- 1:zen_newtable_d 2:zen_fields join zen_function ) /* Function : 配合 api 可以直接產生 table 的 sp Description: 因為只能在相同的 db 執行, 所以在 zenWinzard 或 zenBusiness 都要有此 sp 及 zen_newtable_m/zen_newtable_d 在平台的架構中雖然放在 Wizard Menu 中, 但手改 json 連到 zenBusiness(zenEIS) 等 ERP DB, 因為通常需要新增的 table 都是 MIS 要擴充功能用的 CALL zen_create_table('tmp_test01','2'); 2023-07-07 因為希望參考 iCoder 的作法, 匯入 zen_fields 後, 直接就產生程式(接近一鍵產生程式碼), 所以新增 p_source_typ=2 但是 zen_fields 是 zenWinzard 的 table, 如果是分離型 db 架構, 就無法支援 p_source_typ=2 這很傷腦筋, 怎麼辦? 如果傳入 db ?? 看樣子只能先獨立建立 table (p_source_typ=1), 然後匯入 zen_fields, 再產生 Code, 先這樣吧 2023-08-26 用資料庫的同義字功能, 已解決分離式資料庫的問題 Build Date : 2022/02/16 Modify History Item Who Date Modify Docs ==== ========== ========== ================================================ 1 Michael 2022/02/16 Init 2 Michael 2023/06/28 新增也可以根據 zen_function/zen_fields 來產生 Table 的寫法(必須配合 zen_function 也已經新增定義才行) 3 Michael 2023/07/29 create table 後, 要多 select 0 as code 才不會報錯 4 [改寫者] 2023-11-15 改寫為 MariaDB 版本並最佳化 */ BEGIN DECLARE v_sql LONGTEXT; DECLARE v_rets LONGTEXT; DECLARE v_maxcount INT; DECLARE v_currid INT; DECLARE v_nextrowid INT; DECLARE v_fieldname VARCHAR(100); DECLARE v_field_type VARCHAR(100); DECLARE v_field_len SMALLINT; DECLARE v_is_pk CHAR(1); DECLARE v_is_auto CHAR(1); DECLARE v_sql_tail VARCHAR(100); DECLARE v_sql_pk VARCHAR(100); DECLARE v_row_count INT; -- 創建臨時表來存儲字段信息 DROP TEMPORARY TABLE IF EXISTS temp_table_fields; CREATE TEMPORARY TABLE temp_table_fields ( fieldname VARCHAR(100), field_type VARCHAR(100), field_len SMALLINT, is_pk CHAR(1), is_auto CHAR(1), rowid INT AUTO_INCREMENT PRIMARY KEY ); -- 根據來源類型填充臨時表 IF IFNULL(p_source_type, '1') = '1' THEN INSERT INTO temp_table_fields (fieldname, field_type, field_len, is_pk, is_auto) SELECT fieldname, field_type, field_len, is_pk, is_auto FROM zen_newtable_d WHERE tablename = p_tablename; ELSE -- 使用同義字(Synonym)解決跨資料庫問題 INSERT INTO temp_table_fields (fieldname, field_type, field_len, is_pk, is_auto) SELECT x1.fieldname, CASE WHEN x1.fieldobject IN ('textarea','input-file','link-file','input-image','nvarchar') THEN 'varchar' WHEN x1.fieldobject IN ('int','decimal','smallint') THEN x1.fieldobject WHEN x1.fieldobject IN ('radios','progress') THEN 'smallint' WHEN x1.fieldobject = 'input-number' THEN 'int' WHEN x1.fieldobject IN ('input-datetime','datetime') THEN 'datetime' WHEN x1.fieldobject = 'input-date' THEN 'date' WHEN LOCATE('cycle', x1.fieldobject) > 0 THEN x1.fieldobject -- 獨立判斷 ELSE 'varchar' END field_type, x1.fieldlength AS field_len, CASE WHEN LOCATE(x1.fieldname, x2.mainkey) > 0 THEN 'Y' ELSE 'N' END is_pk, x2.isautoinc AS is_auto FROM zen_fields x1 LEFT JOIN zen_function x2 ON x1.functiontag = x2.functiontag WHERE x1.tablename = p_tablename AND x1.fieldobject <> 'formula'; END IF; -- 初始化變量 SELECT MAX(rowid), MIN(rowid) INTO v_maxcount, v_currid FROM temp_table_fields; SET v_rets = ''; SET v_sql_pk = ''; -- 構建字段定義 WHILE v_currid <= v_maxcount DO -- 取得當前字段信息 SELECT fieldname, field_type, field_len, is_pk, is_auto INTO v_fieldname, v_field_type, v_field_len, v_is_pk, v_is_auto FROM temp_table_fields WHERE rowid = v_currid; SET v_sql_tail = ''; IF v_is_pk = 'Y' THEN SET v_sql_tail = ' NOT NULL'; SET v_sql_pk = CONCAT(v_sql_pk, v_fieldname, ','); END IF; IF v_is_auto = 'Y' THEN SET v_sql_tail = CONCAT(v_sql_tail, ' AUTO_INCREMENT'); END IF; IF LOCATE('transfer', v_field_type) > 0 OR v_field_len < 0 THEN SET v_rets = CONCAT(v_rets, ' ', v_fieldname, ' ', v_field_type, '(255)', v_sql_tail, ','); ELSEIF LOCATE('cycle', v_field_type) > 0 THEN IF v_field_type IN ('cycle-frequency','cycle-weeks','cycle-months') THEN SET v_rets = CONCAT(v_rets, ' ', v_fieldname, ' varchar(200)', v_sql_tail, ','); ELSE SET v_rets = CONCAT(v_rets, ' ', v_fieldname, ' datetime ', v_sql_tail, ','); END IF; ELSEIF LOCATE('char', v_field_type) > 0 THEN IF v_field_len <= 0 THEN SET v_rets = CONCAT(v_rets, ' ', v_fieldname, ' ', v_field_type, '(200)', v_sql_tail, ','); ELSE SET v_rets = CONCAT(v_rets, ' ', v_fieldname, ' ', v_field_type, '(', v_field_len, ')', v_sql_tail, ','); END IF; ELSE SET v_rets = CONCAT(v_rets, ' ', v_fieldname, ' ', v_field_type, v_sql_tail, ','); END IF; -- 取得下一筆資料 SELECT MIN(rowid) INTO v_nextrowid FROM temp_table_fields WHERE rowid > v_currid; SET v_currid = v_nextrowid; END WHILE; -- 處理主鍵定義 IF v_sql_pk = '' THEN SET v_sql_pk = ''; SET v_rets = SUBSTRING(v_rets, 1, CHAR_LENGTH(v_rets) - 1); ELSE SET v_sql_pk = CONCAT(' PRIMARY KEY (', SUBSTRING(v_sql_pk, 1, CHAR_LENGTH(v_sql_pk) - 1), ')'); END IF; -- 只有當有字段定義時才創建表 IF v_rets <> '' THEN -- 檢查表是否存在,如果存在且無數據則刪除 SET @sql_check = CONCAT('SELECT COUNT(*) INTO @row_count FROM information_schema.tables ', 'WHERE table_schema = DATABASE() AND table_name = \'', p_tablename, '\''); PREPARE stmt FROM @sql_check; EXECUTE stmt; DEALLOCATE PREPARE stmt; IF @row_count > 0 THEN SET @sql_check = CONCAT('SELECT COUNT(*) INTO @row_count FROM ', p_tablename); PREPARE stmt FROM @sql_check; EXECUTE stmt; DEALLOCATE PREPARE stmt; IF @row_count <= 0 THEN SET @sql = CONCAT('DROP TABLE ', p_tablename); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END IF; END IF; -- 創建新表 SET v_sql = CONCAT('CREATE TABLE ', p_tablename, '(', v_rets, v_sql_pk, ');'); -- 執行創建表的SQL PREPARE stmt FROM v_sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- 返回成功信息 SELECT 0 AS code, 'OK' AS msg; END IF; END // DELIMITER ;