MySQL函數-根據子節點查詢所有父節點名稱


背景

公司的一個業務系統中有區域表,整個區域是一個樹結構,為了方便根據某一父節點查詢所有葉子節點,提供了一個額外的字段path,按照分隔符存儲了從根節點到當前節點的總路徑。

表結構如下:

create table t_area
(
    area_id       varchar(32)  not null comment '主鍵' primary key,
    area_pid      varchar(32)  null comment '父級區域ID',
    area_name     varchar(30)  null comment '區域名稱',
    level         varchar(2)   null comment '層級 從1開始',
    external_name varchar(30)  null comment '對外名稱',
    flag          varchar(3)   null comment '特殊標記 0=沒有標記 1=特殊入門',
    path          varchar(200) null
)
    comment '區域位置表';

比如,有以下路徑:

  • A樓-13層-1301室
  • A樓-13層-1302室
  • A樓-13層-1303室

那么,

  • 在1301的path字段存儲為:A樓id#13層id#1301id
  • 在1302的path字段存儲為:A樓id#13層id#1302id
  • 在1303的path字段存儲為:A樓id#13層id#1303id

目前的需求是,需要查詢給定葉子節點的完整路徑名稱,但是待查詢的表中只存儲了葉子節點的area_id

有兩種方式可以實現:

  1. 寫一個SQL查詢出葉子節點id,對應的path,在Java層面,按照#切割字符串,得到每一層的area_id,再用SQL查詢出area_id對應的area_name,拼接好返回
  2. 在MySQL中實現一個自定義函數,傳入葉子節點的id,即可獲取完整路徑名稱。

如果使用第二種方式,該業務SQL就變得很簡單,考慮用函數實現。

函數實現

CREATE DEFINER=`sgsv2`@`%` FUNCTION `getFullArea`(`areaId` varchar(50)) RETURNS varchar(50) CHARSET utf8
BEGIN
	set @area_id=areaId;
-- 	select @area_id;
  select path from t_area where area_id = @area_id limit 1 into @path;
-- 	select @path;
	SET @i=2; 
	SET @count=(LENGTH(@path)-LENGTH(REPLACE(@path ,'#',''))) + 1;
	set @returnStr="";
-- 	select @count;
	
	
	WHILE @i <= @count 
	DO
  set @areaTmpId=(SUBSTRING_INDEX(SUBSTRING_INDEX(@path,'#',@i),'#',-1));
-- 	select @areaTmpId;
	select area_name from t_area where area_id = @areaTmpId into @areaTmpName;
-- 	select @areaTmpName;


	if @i > 2 Then
	set @returnStr=concat(@returnStr,'-',@areaTmpName);
	else
	   set @returnStr=concat(@returnStr,@areaTmpName);
	end if;
	
-- 	set @returnStr=concat(@returnStr,'-',@areaTmpName);
-- 	select @returnStr;
	SET @i=@i+1; 
	END WHILE; 
	
-- 	select @returnStr;
  
	RETURN  @returnStr;
END

要點:獲取path后,如何遍歷獲取每層的area_id?

我這里的實現是,先用下面的語句,獲取總area_id的個數

SET @count=(LENGTH(@path)-LENGTH(REPLACE(@path ,'#',''))) + 1;

根據獲得的count數進行遍歷,在遍歷中獲取每一個area_id,關鍵語句如下:

set @areaTmpId=(SUBSTRING_INDEX(SUBSTRING_INDEX(@path,'#',@i),'#',-1));

最后使用concat函數拼接得到最終的結果

set @returnStr=concat(@returnStr,'-',@areaTmpName);

技巧:可以使用存儲過程來調試

在函數中, 無法像存儲過程一樣,使用select @變量名來調試,所以我先把函數主題復制到一個存儲過程中,這樣就可以調試了!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM