SQL 查询:查找连接的联系人,直到三度深度
SQL query: Finding connected contacts until third degree of depth
我正在使用 PostgreSQL 8.2.15 (Greenplum Database 4.3.3.1 build 1),这意味着不支持使用 WITH RECURSIVE。
有样本table:
select * from reports_Table
reporter spammer
AAA BBB
AAA CCC
DDD CCC
DDD BBB
DDD EEE
DDD FFF
EEE DDD
CCC AAA
FFF DDD
BBB AAA
BBB CCC
BBB DDD
通过sql,我试图获取所有记者以及连接到 AAA 的垃圾邮件发送者的列表,直到第三级深度。在上面的示例中,查询的结果将是:
AAA
BBB
CCC
DDD
FFF
EEE
BBB 和 CCC 直接与 AAA 相连,因此是 AAA 的一级连接,
DDD 是 AAA 的二级连接,因为它是通过 CCC 连接的,
FFF 和 EEE 是 AAA 的三度连接,因为它们都是通过 DDD 连接的。
我已经设法在查询中找到这一点,我认为它在逻辑上是可行的,但无法继续,因为似乎无法理解发生的语法错误:
ERROR: syntax error at or near "WHILE"
很可能我使用的版本需要不同的 WHILE LOOP 语法,但我似乎无法修复它。
/*supported tables*/
CREATE TEMP TABLE variables as
select 1 as first_column, 'AAA'::text as specific_reporter, 3 as degreeNumber
CREATE TEMP TABLE CollectedReporters(
specific_reporter text
);
GO
INSERT INTO CollectedReporters
select specific_reporter from variables;
/*main query*/
BEGIN
WHILE (select degreeNumber from variables) >= 1 LOOP
INSERT INTO CollectedReporters
SELECT ct.spammer::text as specific_reporter
FROM reports_Table ct
INNER JOIN CollectedReporters cc ON ct.reporter = cc.specific_reporter::text
LEFT JOIN CollectedReporters cc2 ON ct.spammer = cc2.specific_reporter::text
WHERE cc2.specific_reporter IS NULL;
UPDATE variables
SET degreeNumber = degreeNumber - 1;
END WHILE;
END;
SELECT * FROM CollectedReporters
非常感谢任何帮助!
这里的问题是你不了解数据库语法,我建议你覆盖the guide on PG,这样你会更清楚
- 首先,您只能在 PL/pgSQL 函数内部使用 BEGIN-END 结构,因为它是 PL/pgSQL 语言语法的一部分。在函数外使用时,"BEGIN"表示事务开始,应适当使用
- 当您通过 GUI 工具 运行 查询时,每个查询都应该是正确的 ANSI SQL 查询。 "while" 不是 ANSI SQL 的一部分。但是,它是 MSSQL 中的 T-SQL、Oracle 中的 PL/SQL 和 Postgres
中的 PL/pgSQL 的一部分
- 要在 Greenplum 4.3 及更早版本中使用 PL/pgSQL,您只有一个选择 - 创建一个函数。在 Greenplum 版本 5.0+(从 github 开发构建)中,您还可以在 PL/pgSQL
中使用匿名代码块
这是一个示例:
CREATE OR REPLACE FUNCTION my_function (maxlevel int) returns void as $BODY$
DECLARE
level int = 1;
BEGIN
TRUNCATE CollectedReporters;
WHILE (level <= maxlevel) LOOP
RAISE NOTICE 'Processing level %', level;
INSERT INTO CollectedReporters
SELECT ct.spammer::text as specific_reporter
FROM reports_Table ct
INNER JOIN CollectedReporters cc ON ct.reporter = cc.specific_reporter::text
LEFT JOIN CollectedReporters cc2 ON ct.spammer = cc2.specific_reporter::text
WHERE cc2.specific_reporter IS NULL;
level = level + 1;
END LOOP;
END;
$BODY$ LANGUAGE PLPGSQL VOLATILE;
我正在使用 PostgreSQL 8.2.15 (Greenplum Database 4.3.3.1 build 1),这意味着不支持使用 WITH RECURSIVE。
有样本table:
select * from reports_Table
reporter spammer
AAA BBB
AAA CCC
DDD CCC
DDD BBB
DDD EEE
DDD FFF
EEE DDD
CCC AAA
FFF DDD
BBB AAA
BBB CCC
BBB DDD
通过sql,我试图获取所有记者以及连接到 AAA 的垃圾邮件发送者的列表,直到第三级深度。在上面的示例中,查询的结果将是:
AAA
BBB
CCC
DDD
FFF
EEE
BBB 和 CCC 直接与 AAA 相连,因此是 AAA 的一级连接,
DDD 是 AAA 的二级连接,因为它是通过 CCC 连接的,
FFF 和 EEE 是 AAA 的三度连接,因为它们都是通过 DDD 连接的。
我已经设法在查询中找到这一点,我认为它在逻辑上是可行的,但无法继续,因为似乎无法理解发生的语法错误:
ERROR: syntax error at or near "WHILE"
很可能我使用的版本需要不同的 WHILE LOOP 语法,但我似乎无法修复它。
/*supported tables*/
CREATE TEMP TABLE variables as
select 1 as first_column, 'AAA'::text as specific_reporter, 3 as degreeNumber
CREATE TEMP TABLE CollectedReporters(
specific_reporter text
);
GO
INSERT INTO CollectedReporters
select specific_reporter from variables;
/*main query*/
BEGIN
WHILE (select degreeNumber from variables) >= 1 LOOP
INSERT INTO CollectedReporters
SELECT ct.spammer::text as specific_reporter
FROM reports_Table ct
INNER JOIN CollectedReporters cc ON ct.reporter = cc.specific_reporter::text
LEFT JOIN CollectedReporters cc2 ON ct.spammer = cc2.specific_reporter::text
WHERE cc2.specific_reporter IS NULL;
UPDATE variables
SET degreeNumber = degreeNumber - 1;
END WHILE;
END;
SELECT * FROM CollectedReporters
非常感谢任何帮助!
这里的问题是你不了解数据库语法,我建议你覆盖the guide on PG,这样你会更清楚
- 首先,您只能在 PL/pgSQL 函数内部使用 BEGIN-END 结构,因为它是 PL/pgSQL 语言语法的一部分。在函数外使用时,"BEGIN"表示事务开始,应适当使用
- 当您通过 GUI 工具 运行 查询时,每个查询都应该是正确的 ANSI SQL 查询。 "while" 不是 ANSI SQL 的一部分。但是,它是 MSSQL 中的 T-SQL、Oracle 中的 PL/SQL 和 Postgres 中的 PL/pgSQL 的一部分
- 要在 Greenplum 4.3 及更早版本中使用 PL/pgSQL,您只有一个选择 - 创建一个函数。在 Greenplum 版本 5.0+(从 github 开发构建)中,您还可以在 PL/pgSQL 中使用匿名代码块
这是一个示例:
CREATE OR REPLACE FUNCTION my_function (maxlevel int) returns void as $BODY$
DECLARE
level int = 1;
BEGIN
TRUNCATE CollectedReporters;
WHILE (level <= maxlevel) LOOP
RAISE NOTICE 'Processing level %', level;
INSERT INTO CollectedReporters
SELECT ct.spammer::text as specific_reporter
FROM reports_Table ct
INNER JOIN CollectedReporters cc ON ct.reporter = cc.specific_reporter::text
LEFT JOIN CollectedReporters cc2 ON ct.spammer = cc2.specific_reporter::text
WHERE cc2.specific_reporter IS NULL;
level = level + 1;
END LOOP;
END;
$BODY$ LANGUAGE PLPGSQL VOLATILE;