我有一个 MySQL 数据库,其中包含一个分层组件表(每个非顶级组件都有一个父组件)
它包括一个 SQL 函数GetParents(ComponentID)
,它返回一个以逗号分隔的 parent 列表ComponentID
,从直接 parent 开始并向上。这是按预期正常工作的。
我将该函数复制到GetPath(ComponentID
并试图让它返回Title
而不是ID,并更改顺序,使其从最高父级开始并下降,但被卡住了。我设法将顺序更改,
为 a ->
,并将顶级 ID (0) 更改为(Top Level)
(顶级资产除外!),但无法弄清楚如何获取标题而不是 ID。
不幸的是 sqlfiddle 不喜欢DELIMITER
(任何替代方案?)但下面是代码,包括满足以下示例的表模式和插入:
SELECT GetParents(11);
应该返回4,1,0
。这现在可以正常工作,我只是为了完整性而将其包括在内。
SELECT GetPath(11);
目前返回(Top Level) -> 1 -> 4
,但我想让它返回(Top Level) -> Cars -> Car 1
DROP TABLE IF EXISTS `Components`;
CREATE TABLE `Components` (
`ComponentID` int(11) NOT NULL,
`ParentComponentID` int(11) NOT NULL,
`Title` varchar(250) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `Components`
ADD PRIMARY KEY (`ComponentID`);
ALTER TABLE `Components`
MODIFY `ComponentID` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;
INSERT INTO Components (ParentComponentID, Title) VALUES
(0, 'Cars'),(0,'Trucks'),(0,'Boats');
INSERT INTO Components (ParentComponentID, Title) VALUES
(1, 'Car 1'),(1,'Car 2'),(1,'Car 3'),(2,'Truck 1'),(3,'Boat 3');
INSERT INTO Components (ParentComponentID, Title) VALUES
(4, 'Wheel 1'),(4,'Wheel 2'),(4,'Wheel 3'),(4,'Wheel 4');
INSERT INTO Components (ParentComponentID, Title) VALUES
(5, 'Wheel 1'),(5,'Wheel 2'),(5,'Wheel 3'),(5,'Wheel 4');
-- Functions
DELIMITER $$
DROP FUNCTION IF EXISTS `GetParents` $$
CREATE FUNCTION `GetParents` (GivenID VARCHAR(1024)) RETURNS varchar(1024) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE rv,q,queue,queue_children,front_id VARCHAR(1024);
DECLARE queue_length,pos INT;
SET rv = '';
SET queue = GivenID;
SET queue_length = 1;
WHILE queue_length > 0 DO
SET front_id = queue;
IF queue_length = 1 THEN
SET queue = '';
ELSE
SET pos = LOCATE(',',queue) + 1;
SET q = SUBSTR(queue,pos);
SET queue = q;
END IF;
SET queue_length = queue_length - 1;
SELECT IFNULL(qc,'') INTO queue_children
FROM (SELECT GROUP_CONCAT(ParentComponentID) qc
FROM Components WHERE ComponentID = front_id AND ParentComponentID!=ComponentID) A;
IF LENGTH(queue_children) = 0 THEN
IF LENGTH(queue) = 0 THEN
SET queue_length = 0;
END IF;
ELSE
IF LENGTH(rv) = 0 THEN
SET rv = queue_children;
ELSE
SET rv = CONCAT(rv,',',queue_children);
END IF;
IF LENGTH(queue) = 0 THEN
SET queue = queue_children;
ELSE
SET queue = CONCAT(queue,',',queue_children);
END IF;
SET queue_length = LENGTH(queue) - LENGTH(REPLACE(queue,',','')) + 1;
END IF;
END WHILE;
RETURN rv;
END $$
DROP FUNCTION IF EXISTS `GetPath` $$
CREATE FUNCTION `GetPath` (GivenID VARCHAR(1024)) RETURNS varchar(1024) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE rv,q,queue,queue_children,front_id VARCHAR(1024);
DECLARE queue_length,pos INT;
SET rv = '';
SET queue = GivenID;
SET queue_length = 1;
WHILE queue_length > 0 DO
SET front_id = queue;
IF queue_length = 1 THEN
SET queue = '';
ELSE
SET pos = LOCATE(',',queue) + 1;
SET q = SUBSTR(queue,pos);
SET queue = q;
END IF;
SET queue_length = queue_length - 1;
SELECT IFNULL(qc,'') INTO queue_children
FROM (SELECT GROUP_CONCAT(ParentComponentID) qc
FROM Components WHERE ComponentID = front_id AND ParentComponentID!=ComponentID) A;
IF LENGTH(queue_children) = 0 THEN
IF LENGTH(queue) = 0 THEN
SET queue_length = 0;
END IF;
ELSE
IF LENGTH(rv) = 0 THEN
SET rv = queue_children;
ELSE
IF (queue_children = 0) THEN
SET rv = CONCAT('(Top Level) -> ',rv);
ELSE
SET rv = CONCAT(queue_children,' -> ',rv);
END IF;
END IF;
IF LENGTH(queue) = 0 THEN
SET queue = queue_children;
ELSE
SET queue = CONCAT(queue,',',queue_children);
END IF;
SET queue_length = LENGTH(queue) - LENGTH(REPLACE(queue,',','')) + 1;
END IF;
END WHILE;
RETURN rv;
END $$
DELIMITER ;
该函数将在 的上下文中调用SELECT getPath(ComponentID) FROM Components
,该表可能有许多条目,因此最好有一个高效的算法!
谢谢!