将脚本从 MSSQL 转换为 PL/pgSQL
Posted
技术标签:
【中文标题】将脚本从 MSSQL 转换为 PL/pgSQL【英文标题】:Converting a script from MSSQL to PL/pgSQL 【发布时间】:2013-06-10 18:48:27 【问题描述】:我刚开始使用 EVE 静态转储,其中包含许多包含游戏数据的表格,例如太阳能系统连接的列表,这就是我正在处理的内容。 我想制作一个网页,让您可以过滤掉系统,第一步是获取附近系统的列表,以及到它们的距离。
我找到了一个用于 MSSQL 的脚本
--By Joanna Davaham http://forum.eveuniversity.org/viewtopic.php?t=44601&p=396107#p424943
--set values
DECLARE @jumpsAway INT =10
DECLARE @MiddleSystemName VARCHAR(50) = 'Aldrat'
DECLARE @Level INT =1
IF OBJECT_ID('tempdb..#map') IS NOT NULL
DROP TABLE #map
CREATE TABLE #map
(fromSolarSystemID INT, toSolarSystemID INT, Level INT)
INSERT INTO #map
SELECT -1, mSS.solarSystemID, 0 FROM mapSolarSystems mSS
WHERE mSS.solarSystemName= @MiddleSystemName
WHILE @Level <= @jumpsAway
BEGIN
INSERT INTO #map
SELECT mSSJ.fromSolarSystemID, mSSJ.toSolarSystemID, @Level FROM mapSolarSystemJumps mSSJ
WHERE mSSJ.fromSolarSystemID IN (SELECT toSolarSystemID FROM #map WHERE Level = @Level-1)
AND mSSJ.fromSolarSystemID NOT IN (SELECT fromSolarSystemID FROM #map)
SET @Level=@Level+1
END
SELECT m.*, mSS.solarSystemName, mSS.security FROM #map m
JOIN mapSolarSystems mSS ON m.toSolarSystemID=mSS.solarSystemID
--WHERE mSS.security<0.45 --uncomment to check all nearby lowsec system
我知道我可能只使用 MSSQL 版本的转储,但我也想进一步了解如何更好地使用 PostgreSQL。
我了解它在做什么以及一切,但我对 PL/pgSQL 的理解还不够好,无法使其正常工作。
我的尝试是
CREATE FUNCTION near(VARCHAR, INTEGER) RETURNS TABLE(fromID INT,toID INT,jumps INT,name VARCHAR,security VARCHAR) AS $$
DECLARE --Declaration from here http://www.postgresql.org/docs/9.1/static/plpgsql-declarations.html
MiddleSystemName ALIAS FOR $1;
jumpsAway ALIAS FOR $2;
jumps INTEGER :=1;
BEGIN
--http://***.com/questions/11979154/select-into-to-create-a-table-in-pl-pgsql
CREATE TEMP TABLE map AS
SELECT -1, mSS.solarSystemID, 0
FROM mapSolarSystems mSS
WHERE mSS.solarSystemName= MiddleSystemName;
LOOP
--http://www.postgresql.org/docs/9.1/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN
--If you don't do it with execute, you can only do one row, I guess?
EXECUTE 'SELECT
|| mSSJ.fromSolarSystemID,
|| mSSJ.toSolarSystemID,
|| $1
|| FROM
|| mapSolarSystemJumps mSSJ
|| WHERE
|| mSSJ.fromSolarSystemID EXISTS (SELECT toSolarSystemID FROM map WHERE jumps = $1 - 1)
|| AND mSSJ.fromSolarSystemID NOT EXISTS (SELECT fromSolarSystemID FROM map)'
INTO map
USING jumps;
jumps := jumps + 1
EXIT WHEN jumps > jumpsAway;
END LOOP;
RETURN QUERY SELECT m.*,mSS.solarSystemName, mSS.security FROM JOIN mapSolarSystems mSS ON m.toSolarSystemID = mSS.solarSystemID;
END;
$$ LANGUAGE plpgsql;
而产生的错误是
Error is
ERROR: "map" is not a known variable
LINE 27: INTO map
^
感谢大家的帮助。
【问题讨论】:
你能比a thing
更具体吗?您可以将相关的 sn-ps 复制到问题中以使其对人们有用,而无需转到 pastebin 链接吗? What have you tried?
我不认为这对我想要做的事情很重要,但我想要做的事情是让我通过启动系统附近的系统进行过滤。第一步是获取附近系统的列表,以及它们的距离。我将对其进行编辑,以便代码在这里,对此感到抱歉。我尝试的是第二个链接。
【参考方案1】:
PL/pgSQL
这应该是对 plpgsql 的有效翻译:
CREATE OR REPLACE FUNCTION f_near(_middlesystemname text, _jumpsaway int)
RETURNS TABLE(fromid int, toid int, jumps int, name text, security text) AS
$func$
DECLARE
_jumps integer;
BEGIN
CREATE TEMP TABLE map AS
SELECT -1 AS "fromSolarSystemID"
,m."solarSystemID" AS "toSolarSystemID"
,0 AS level
FROM "mapSolarSystems" m
WHERE "solarSystemName" = _middlesystemname;
-- potentially add indexes on the temp table and ANALYZE if it gets big
FOR _jumps IN 1 .. _jumpsaway LOOP
INSERT INTO map ("fromSolarSystemID", "toSolarSystemID", level)
SELECT sj."fromSolarSystemID", sj."toSolarSystemID", _jumps AS level
FROM "mapSolarSystemJumps" sj
JOIN map m ON m."toSolarSystemID" = sj."fromSolarSystemID"
AND m."level" = _jumps - 1
LEFT JOIN map mx ON mx."fromSolarSystemID" = sj."fromSolarSystemID"
WHERE mx."fromSolarSystemID" IS NULL;
END LOOP;
RETURN QUERY
SELECT m.*, s."solarSystemName", s."security"
FROM map m
JOIN "mapSolarSystems" s ON m."toSolarSystemID" = s."solarSystemID";
END
$func$ LANGUAGE plpgsql;
递归 CTE - 似乎不起作用
这个带有递归 CTE 的简短 SQL 查询应该已经完成了:
WITH RECURSIVE map AS (
SELECT -1 AS fromsolarsystemid, m.solarsystemid, 0 AS level
FROM mapsolarsystems m
WHERE m.solarsystemname = from_id
UNION ALL
SELECT sj.fromsolarsystemid, sj.tosolarsystemid, level + 1
FROM mapsolarsystemjumps sj
JOIN map m USING (level)
LEFT JOIN map mx USING (fromsolarsystemid)
WHERE sj.fromsolarsystemid = m.tosolarsystemid
AND mx.fromsolarsystemid IS NULL
AND m.level < 10 -- jumpsAway
)
SELECT m.*, s.solarsystemname, s.security
FROM map m
JOIN mapsolarsystems s ON m.tosolarsystemid = s.solarsystemid
-- WHERE s.security < 0.45 -- uncomment to check all nearby lowsec system
但是:
ERROR: recursive reference to query "map" must not appear within an outer join LINE 9: LEFT JOIN map mx USING (fromsolarsystemid)
【讨论】:
这行不通,因为我没有名为 map 的表,我应该只做一个吗? @Scuzzball:你不需要一个名为 map 的表。它只是 CTE 工作表的名称。您只需要mapsolarsystems 和mapsolarsystemjumps。 然而,测试这个我发现我们不能在递归术语中对工作表进行左连接。所以我的解决方案不会成功。我会提供一个plpgsql解决方案... 你想让我把我正在运行的数据给你吗? @A small data sample to test code总是是个好主意(在您的问题中)。没有它,我就在盲目地写作。但我很快就会准备好在黑暗中开枪。pg_dump -t 'map*' evesd > mapStuff
的结果是http://uf.serveftp.com/files/mapStuff 似乎将我设置为用户和东西,对此感到抱歉。以上是关于将脚本从 MSSQL 转换为 PL/pgSQL的主要内容,如果未能解决你的问题,请参考以下文章
PL/PgSQL:没有函数匹配给定的名称和参数类型。您可能需要添加显式类型转换