【问题标题】:SQL query: Finding connected contacts until third degree of depthSQL 查询:查找连接的联系人直到第三度深度
【发布时间】:2016-03-22 14:50:04
【问题描述】:

我使用的是 PostgreSQL 8.2.15(Greenplum Database 4.3.3.1 build 1),这意味着不支持使用 WITH RECURSIVE。

有一个示例表:

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 的 1 级连接,
DDD 是 AAA 的 2 度连接,因为它是通过 CCC 连接的,
FFF 和 EEE 是 AAA 的 3 度连接,因为它们都是通过 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

非常感谢任何帮助!

【问题讨论】:

  • 我认为您应该包含发生的错误以帮助我们理解问题。此外,您应该使用正确的缩进更好地格式化您的代码
  • 根据您的样本数据,bbb 是“1 度”而fff 是“3 度”是怎么回事。我不明白你是如何从样本数据中得出这个结论的。
  • 我认为你可以通过递归查询有效地做到这一点,WITH RECURSIVE in Postgres。 postgresql.org/docs/8.4/static/queries-with.html
  • 问题是关于Greenplum,不支持WITH RECURSIVE
  • 这里你应该清楚地说明你正在解决的问题。显示您的输入和您想要达到的结果。说明如何计算结果。您的报告/垃圾邮件发送者示例没有提供信息 - 很明显您正在处理图表,但它是否有针对性?你想找到特定节点的所有后代或祖先吗?你想如何处理周期?

标签: sql hierarchical-data greenplum


【解决方案1】:

这里的问题是你不了解数据库语法,我建议你覆盖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;

【讨论】:

    猜你喜欢
    • 2012-10-03
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 2023-03-13
    • 2017-01-11
    • 1970-01-01
    • 1970-01-01
    • 2018-02-08
    相关资源
    最近更新 更多