我有一个存储过程:
DROP PROCEDURE IF EXISTS dijResolve;
DELIMITER |
CREATE PROCEDURE dijResolve( pFromNodeName VARCHAR(20), pToNodeName VARCHAR(20) )
BEGIN
DECLARE vFromNodeID, vToNodeID, vNodeID, vCost, vPathID INT;
CREATE TEMPORARY TABLE new_dijnodes engine=memory AS SELECT * FROM dijnodes;
CREATE TEMPORARY TABLE new_dijpaths AS SELECT * FROM dijpaths;
-- null out path info in the nodes table
UPDATE new_dijnodes SET PathID = NULL,Cost = NULL,Calculated = 0;
-- find nodeIDs referenced by input params
SET vFromNodeID = ( SELECT NodeID FROM new_dijnodes WHERE NodeName = pFromNodeName );
IF vFromNodeID IS NULL THEN
SELECT CONCAT('From node name ', pFromNodeName, ' not found.' );
ELSE
BEGIN
-- start at src node
SET vNodeID = vFromNodeID;
SET vToNodeID = ( SELECT NodeID FROM new_dijnodes WHERE NodeName = pToNodeName );
IF vToNodeID IS NULL THEN
SELECT CONCAT('From node name ', pToNodeName, ' not found.' );
ELSE
BEGIN
-- calculate path costs till all are done
UPDATE new_dijnodes SET Cost=0 WHERE NodeID = vFromNodeID;
WHILE vNodeID IS NOT NULL DO
BEGIN
UPDATE
new_dijnodes AS src
JOIN new_dijpaths AS paths ON paths.FromNodeID = src.NodeID
JOIN new_dijnodes AS dest ON dest.NodeID = Paths.ToNodeID
SET dest.Cost = CASE
WHEN dest.Cost IS NULL THEN src.Cost + Paths.Cost
WHEN src.Cost + Paths.Cost < dest.Cost THEN src.Cost + Paths.Cost
ELSE dest.Cost
END,
dest.PathID = Paths.PathID
WHERE
src.NodeID = vNodeID
AND (dest.Cost IS NULL OR src.Cost + Paths.Cost < dest.Cost)
AND dest.Calculated = 0;
UPDATE new_dijnodes SET Calculated = 1 WHERE NodeID = vNodeID;
SET vNodeID = ( SELECT nodeID FROM new_dijnodes
WHERE Calculated = 0 AND Cost IS NOT NULL
ORDER BY Cost LIMIT 1
);
END;
END WHILE;
END;
END IF;
END;
END IF;
IF EXISTS( SELECT 1 FROM new_dijnodes WHERE NodeID = vToNodeID AND Cost IS NULL ) THEN
-- problem, cannot proceed
SELECT CONCAT( 'Node ',vNodeID, ' missed.' );
ELSE
BEGIN
-- write itinerary to map table
DROP TEMPORARY TABLE IF EXISTS map;
CREATE TEMPORARY TABLE map (
RowID INT PRIMARY KEY AUTO_INCREMENT,
FromNodeName VARCHAR(20),
ToNodeName VARCHAR(20),
Cost INT
) ENGINE=MEMORY;
WHILE vFromNodeID <> vToNodeID DO
BEGIN
SELECT
src.NodeName,dest.NodeName,dest.Cost,dest.PathID
INTO vFromNodeName, vToNodeName, vCost, vPathID
FROM
new_dijnodes AS dest
JOIN new_dijpaths AS Paths ON Paths.PathID = dest.PathID
JOIN new_dijnodes AS src ON src.NodeID = Paths.FromNodeID
WHERE dest.NodeID = vToNodeID;
INSERT INTO Map(FromNodeName,ToNodeName,Cost) VALUES(vFromNodeName,vToNodeName,vCost);
SET vToNodeID = (SELECT FromNodeID FROM new_dijpaths WHERE PathID = vPathID);
END;
END WHILE;
SELECT FromNodeName,ToNodeName,Cost FROM Map ORDER BY RowID DESC;
DROP TEMPORARY TABLE Map;
END;
END IF;
END;
|
DELIMITER ;
此功能取自本网站 http://www.artfulsoftware.com/infotree/qrytip.php?id=766
我已将其更改为能够对临时表进行计算,因此不需要在表中保存数据。但是我遇到了一个问题,Mysql不允许用其他名称调用临时表。所以在上面的代码中,我将面临一个错误,即
#1137 - Can't reopen table: 'src'
上述错误来自此查询
UPDATE
new_dijnodes AS src
JOIN new_dijpaths AS paths ON paths.FromNodeID = src.NodeID
JOIN new_dijnodes AS dest ON dest.NodeID = Paths.ToNodeID
SET dest.Cost = CASE
WHEN dest.Cost IS NULL THEN src.Cost + Paths.Cost
WHEN src.Cost + Paths.Cost < dest.Cost THEN src.Cost + Paths.Cost
ELSE dest.Cost
END,
dest.PathID = Paths.PathID
WHERE
src.NodeID = vNodeID
AND (dest.Cost IS NULL OR src.Cost + Paths.Cost < dest.Cost)
AND dest.Calculated = 0;
这是我的表的http://sqlfiddle.com/#!9/bc5a01c数据
正如您所看到的,上面的查询将同一个表连接到src
一次,再次连接为dest
并更新其字段。我试图创建另一个new_dijnodes
,但我无法使其工作,这是我的尝试
DROP PROCEDURE IF EXISTS dijResolve;
DELIMITER |
CREATE PROCEDURE dijResolve( pFromNodeName VARCHAR(20), pToNodeName VARCHAR(20) )
BEGIN
DECLARE vFromNodeID, vToNodeID, vNodeID, vCost, vPathID INT;
DECLARE vFromNodeName, vToNodeName VARCHAR(20);
DROP TEMPORARY TABLE IF EXISTS new_dijnodes;
DROP TEMPORARY TABLE IF EXISTS new_dijpaths;
CREATE TEMPORARY TABLE new_dijnodes engine=memory AS SELECT * FROM dijnodes;
CREATE TEMPORARY TABLE new_dijpaths AS SELECT * FROM dijpaths;
-- null out path info in the nodes table
UPDATE new_dijnodes SET PathID = NULL,Cost = NULL,Calculated = 0;
-- find nodeIDs referenced by input params
SET vFromNodeID = ( SELECT NodeID FROM new_dijnodes WHERE NodeName = pFromNodeName );
IF vFromNodeID IS NULL THEN
SELECT CONCAT('From node name ', pFromNodeName, ' not found.' );
ELSE
BEGIN
-- start at src node
SET vNodeID = vFromNodeID;
SET vToNodeID = ( SELECT NodeID FROM new_dijnodes WHERE NodeName = pToNodeName );
IF vToNodeID IS NULL THEN
SELECT CONCAT('From node name ', pToNodeName, ' not found.' );
ELSE
BEGIN
-- calculate path costs till all are done
UPDATE new_dijnodes SET Cost=0 WHERE NodeID = vFromNodeID;
WHILE vNodeID IS NOT NULL DO
BEGIN
DROP TEMPORARY TABLE IF EXISTS new_dijnodes_dst;
CREATE TEMPORARY TABLE new_dijnodes_dst AS SELECT * FROM new_dijnodes;
UPDATE
new_dijnodes
JOIN new_dijpaths ON new_dijpaths.FromNodeID = new_dijnodes.NodeID
JOIN new_dijnodes_dst ON new_dijnodes_dst.NodeID = new_dijpaths.ToNodeID
SET new_dijnodes_dst.Cost = CASE
WHEN new_dijnodes_dst.Cost IS NULL THEN new_dijnodes.Cost + new_dijpaths.Cost
WHEN new_dijnodes.Cost + new_dijpaths.Cost < new_dijnodes_dst.Cost THEN new_dijnodes.Cost + new_dijpaths.Cost
ELSE new_dijnodes_dst.Cost
END,
new_dijnodes_dst.PathID = new_dijpaths.PathID
WHERE
new_dijnodes.NodeID = vNodeID
AND (new_dijnodes_dst.Cost IS NULL OR new_dijnodes.Cost + new_dijpaths.Cost < new_dijnodes_dst.Cost)
AND new_dijnodes_dst.Calculated = 0;
UPDATE new_dijnodes SET Calculated = 1 WHERE NodeID = vNodeID;
SET vNodeID = ( SELECT nodeID FROM new_dijnodes
WHERE Calculated = 0 AND Cost IS NOT NULL
ORDER BY Cost LIMIT 1
);
END;
END WHILE;
END;
END IF;
END;
END IF;
IF EXISTS( SELECT 1 FROM new_dijnodes WHERE NodeID = vToNodeID AND Cost IS NULL ) THEN
-- problem, cannot proceed
SELECT CONCAT( 'Node ',vNodeID, ' missed.' );
ELSE
BEGIN
-- write itinerary to map table
DROP TEMPORARY TABLE IF EXISTS map;
CREATE TEMPORARY TABLE map (
RowID INT PRIMARY KEY AUTO_INCREMENT,
FromNodeName VARCHAR(20),
ToNodeName VARCHAR(20),
Cost INT
) ENGINE=MEMORY;
WHILE vFromNodeID <> vToNodeID DO
BEGIN
DROP TEMPORARY TABLE IF EXISTS new_dijnodes_src;
CREATE TEMPORARY TABLE new_dijnodes_src AS SELECT * FROM new_dijnodes;
SELECT
new_dijnodes_src.NodeName,new_dijnodes.NodeName,new_dijnodes.Cost,new_dijnodes.PathID
INTO vFromNodeName, vToNodeName, vCost, vPathID
FROM
new_dijnodes
JOIN new_dijpaths ON new_dijpaths.PathID = new_dijnodes.PathID
JOIN new_dijnodes_src ON new_dijnodes_src.NodeID = new_dijpaths.FromNodeID
WHERE new_dijnodes.NodeID = vToNodeID;
INSERT INTO Map(FromNodeName,ToNodeName,Cost) VALUES(vFromNodeName,vToNodeName,vCost);
SET vToNodeID = (SELECT FromNodeID FROM new_dijpaths WHERE PathID = vPathID);
END;
END WHILE;
SELECT FromNodeName,ToNodeName,Cost FROM Map ORDER BY RowID DESC;
DROP TEMPORARY TABLE Map;
END;
END IF;
END;
|
DELIMITER ;
但它始终返回SELECT CONCAT( 'Node ',vNodeID, ' missed.' );
,因为它更新new_dijnodes_dst
,即表格重复。
我也无法创建任何真实的表,因为此过程对于每个用户都是唯一的,并且对于多用户来说它的处理并不容易。 有哪些解决方案可以解决这个问题? 谢谢
答案 0 :(得分:1)
MySQL doc建议
您不能在同一查询中多次引用TEMPORARY表
请参阅this主题。最实用的解决方案似乎是
由于你的特定问题是使用自联接更新而你不想要永久表,我建议制作重复的临时表是最合适的选择。
我尝试创建另一个new_dijnodes,但我无法使其正常工作
你能否分享一下你在哪里遇到麻烦?
答案 1 :(得分:1)
添加另一个答案,因为评论时间过长。
在更新语句之后,我将临时表的两个实例都放在同一页面上,现在它正常工作。您可以看到输出here
请使用以下存储过程。
DROP PROCEDURE IF EXISTS dijResolve;
DELIMITER |
CREATE PROCEDURE dijResolve( pFromNodeName VARCHAR(20), pToNodeName VARCHAR(20) )
BEGIN
DECLARE vFromNodeID, vToNodeID, vNodeID, vCost, vPathID INT;
DECLARE vFromNodeName, vToNodeName VARCHAR(20);
DROP TEMPORARY TABLE IF EXISTS new_dijnodes;
DROP TEMPORARY TABLE IF EXISTS new_dijpaths;
CREATE TEMPORARY TABLE new_dijnodes engine=memory AS SELECT * FROM dijnodes;
CREATE TEMPORARY TABLE new_dijpaths AS SELECT * FROM dijpaths;
-- null out path info in the nodes table
UPDATE new_dijnodes SET PathID = NULL,Cost = NULL,Calculated = 0;
-- find nodeIDs referenced by input params
SET vFromNodeID = ( SELECT NodeID FROM new_dijnodes WHERE NodeName = pFromNodeName );
IF vFromNodeID IS NULL THEN
SELECT CONCAT('From node name ', pFromNodeName, ' not found.' );
ELSE
BEGIN
-- start at src node
SET vNodeID = vFromNodeID;
SET vToNodeID = ( SELECT NodeID FROM new_dijnodes WHERE NodeName = pToNodeName );
IF vToNodeID IS NULL THEN
SELECT CONCAT('From node name ', pToNodeName, ' not found.' );
ELSE
BEGIN
-- calculate path costs till all are done
UPDATE new_dijnodes SET Cost=0 WHERE NodeID = vFromNodeID;
WHILE vNodeID IS NOT NULL DO
BEGIN
DROP TEMPORARY TABLE IF EXISTS new_dijnodes_dst;
CREATE TEMPORARY TABLE new_dijnodes_dst AS SELECT * FROM new_dijnodes;
UPDATE
new_dijnodes
JOIN new_dijpaths ON new_dijpaths.FromNodeID = new_dijnodes.NodeID
JOIN new_dijnodes_dst ON new_dijnodes_dst.NodeID = new_dijpaths.ToNodeID
SET new_dijnodes_dst.Cost = CASE
WHEN new_dijnodes_dst.Cost IS NULL THEN new_dijnodes.Cost + new_dijpaths.Cost
WHEN new_dijnodes.Cost + new_dijpaths.Cost < new_dijnodes_dst.Cost THEN new_dijnodes.Cost + new_dijpaths.Cost
ELSE new_dijnodes_dst.Cost
END,
new_dijnodes_dst.PathID = new_dijpaths.PathID
WHERE
new_dijnodes.NodeID = vNodeID
AND (new_dijnodes_dst.Cost IS NULL OR new_dijnodes.Cost + new_dijpaths.Cost < new_dijnodes_dst.Cost)
AND new_dijnodes_dst.Calculated = 0;
DROP TEMPORARY TABLE IF EXISTS new_dijnodes;
CREATE TEMPORARY TABLE new_dijnodes AS SELECT * FROM new_dijnodes_dst;
UPDATE new_dijnodes SET Calculated = 1 WHERE NodeID = vNodeID;
SET vNodeID = ( SELECT nodeID FROM new_dijnodes
WHERE Calculated = 0 AND Cost IS NOT NULL
ORDER BY Cost LIMIT 1
);
END;
END WHILE;
END;
END IF;
END;
END IF;
IF EXISTS( SELECT 1 FROM new_dijnodes WHERE NodeID = vToNodeID AND Cost IS NULL ) THEN
-- problem, cannot proceed
SELECT CONCAT( 'Node ',vNodeID, ' missed.' );
ELSE
BEGIN
-- write itinerary to map table
DROP TEMPORARY TABLE IF EXISTS map;
CREATE TEMPORARY TABLE map (
RowID INT PRIMARY KEY AUTO_INCREMENT,
FromNodeName VARCHAR(20),
ToNodeName VARCHAR(20),
Cost INT
) ENGINE=MEMORY;
WHILE vFromNodeID <> vToNodeID DO
BEGIN
DROP TEMPORARY TABLE IF EXISTS new_dijnodes_src;
CREATE TEMPORARY TABLE new_dijnodes_src AS SELECT * FROM new_dijnodes;
SELECT
new_dijnodes_src.NodeName,new_dijnodes.NodeName,new_dijnodes.Cost,new_dijnodes.PathID
INTO vFromNodeName, vToNodeName, vCost, vPathID
FROM
new_dijnodes
JOIN new_dijpaths ON new_dijpaths.PathID = new_dijnodes.PathID
JOIN new_dijnodes_src ON new_dijnodes_src.NodeID = new_dijpaths.FromNodeID
WHERE new_dijnodes.NodeID = vToNodeID;
INSERT INTO Map(FromNodeName,ToNodeName,Cost) VALUES(vFromNodeName,vToNodeName,vCost);
SET vToNodeID = (SELECT FromNodeID FROM new_dijpaths WHERE PathID = vPathID);
END;
END WHILE;
SELECT FromNodeName,ToNodeName,Cost FROM Map ORDER BY RowID DESC;
DROP TEMPORARY TABLE Map;
END;
END IF;
END;
|
DELIMITER ;