在進行數據庫移植的過程中,遇到了對樹進行遞歸查詢的問題。
在SQL server 中,很容易實現。如下圖:
WITH Tree AS (SELECT T1.F_EnergyItemCode FROM T_DT_EnergyItemDict AS T1 WHERE T1.F_EnergyItemCode = @EnergyItemCode UNION ALL SELECT T2.F_EnergyItemCode FROM T_DT_EnergyItemDict AS T2 INNER JOIN Tree ON T2.F_ParentItemCode = Tree.F_EnergyItemCode)
而mysql 不支持with as。
實現方法:
建立一個存儲過程:
CREATE DEFINER=`root`@`localhost` PROCEDURE `spg_GetChildLst`(IN `p_id` varchar(100),IN `p_col_name` varchar(100),IN `p_col_p_name` varchar(100),IN `p_t_name` varchar(100),OUT `p_RetVal` varchar(1000)) BEGIN /** 遞歸查找從屬項,輸入參數分別為具體的父項ID,查找的ID列名,父項的ID列名,和表名。輸出一個所有ID的字符串。 **/ DECLARE sTemp VARCHAR(1000); DECLARE sTempChd VARCHAR(1000); declare v_sql varchar(500); -- 需要執行的SQL語句 SET sTemp = '$'; SET sTempChd =cast(p_id as CHAR); set v_sql= concat('SELECT group_concat(',p_col_name,' ) INTO @sTempChd FROM ',p_t_name,' where FIND_IN_SET(',p_col_p_name,',@sTempChd)>0'); set @v_sql=v_sql; -- 注意很重要,將連成成的字符串賦值給一個變量(可以之前沒有定義,但要以@開頭) WHILE sTempChd is not null DO SET sTemp = concat(sTemp,',',sTempChd); SET @sTempChd=sTempChd; prepare stmt from @v_sql; -- 預處理需要執行的動態SQL,其中stmt是一個變量 EXECUTE stmt; -- 執行SQL語句 deallocate prepare stmt; -- 釋放掉預處理段 SET sTempChd=@sTempChd; -- SELECT group_concat(F_EnergyItemCode) INTO sTempChd FROM T_DT_EnergyItemDict where FIND_IN_SET(F_ParentItemCode,sTempChd)>0; END WHILE; SET p_RetVal=sTemp; END
為什么要建立存儲過程那?因為我們項目很多業務都涉及到樹這種從屬關系,所以抽象出來,每個表使用遞歸的時候,直接輸入一些字段名和ID和表名即可。
而函數是不支持執行動態SQL的。
然后在實際項目中,調用這個存儲過程即可。、
例如:
CALL spg_GetChildLst(@EnergyItemCode,'F_EnergyItemCode','F_ParentItemCode','T_DT_EnergyItemDict',@stmp); INSERT INTO TmpP01 (F_Id, F_Type) SELECT F_EnergyItemCode, 0 FROM ( SELECT F_EnergyItemCode FROM T_DT_EnergyItemDict WHERE FIND_IN_SET(F_EnergyItemCode, @stmp) ) AS T;
總結:關鍵點就是mysql動態執行SQL,並且通過@變量名的形式獲取返回值。
然后就是FIND_IN_SET()這個函數。