POSTGRESQL:使用连接表的案例

Posted

技术标签:

【中文标题】POSTGRESQL:使用连接表的案例【英文标题】:POSTGRESQL: Using case with joined tables 【发布时间】:2021-04-15 02:20:59 【问题描述】:

我是 Postgresql 新手,所以在这里仍然有点挣扎。请温柔一点。

我要加入三个表,并希望能够使用 case 语句来引入另一列,该列基于另一列带来所需值。我猜我的 INNER JOIN 和 CASE 语句是从前到后的,但我不确定如何在不破坏意图的情况下重新排列它们。

基本上:如果model_best_fit == SUNNY,那么我想要一个名为applied_f_model_hours_above4k 的新列具有来自hourabove4k_sunny 列的值

代码示例:

SELECT *
    FROM px_fuel_weathercell
        INNER JOIN f_descriptions ON px_f_weathercell.px_id = f_descriptions.fuel_id
        INNER JOIN dailywx ON px_f_weathercell.fid_new_wx_cells = dailywx.location
        CASE best_model_fit
            WHEN 'SUNNY' then hoursabove4k_sunny
        END applied_f_model_hours_above4k
    WHERE best_model_fit = 'SUNNY' /* limiting my test case here, clause will be removed later */
LIMIT 1000; 

错误如下:

ERROR:  syntax error at or near "CASE"
LINE 5:   CASE best_model_fit
          ^
SQL state: 42601
Character: 210

感谢您提供的任何帮助。

奖励积分:CASE 似乎很慢。运行此查询需要 45 秒。 dailywx 有 400,000 行,px_f_weathercell 有 6,000,000 行。有没有更快的方法来做到这一点?

编辑: 进行了以下编辑,当所需的列中包含数字(包括 0)时,不会得到一个充满空值的列。两列都是 double 类型。

EDIT2:更新了几个表名以指示列的来源。还更新为显示左连接。我还使用 PGTune 设置了一些推荐设置,以解决进程受磁盘限制的情况。我还在 px_f_weathercell.fid_new_wx_cells 和 px_f_weathercell.px_id 上设置了索引。这导致在大约 5-7 秒内返回 100,000 条记录。 不过,我仍在从 CASE 语句中接收空值

SELECT *,
    CASE best_model_fit
        WHEN 'SUNNY' then dailywx.hoursabove4k_sunny
    END applied_f_model_hours_above4k
    FROM px_fuel_weathercell
        LEFT JOIN f_descriptions ON px_f_weathercell.px_id = f_descriptions.fuel_id
        LEFT JOIN dailywx ON px_f_weathercell.fid_new_wx_cells = dailywx.location
    WHERE fuel_descriptions.best_model_fit = 'SUNNY' /* limiting my test case here, clause will be removed later */
LIMIT 1000; 

【问题讨论】:

将 case expression 移动到你的select(这是确定列数的地方) 我已经尝试了我认为您的意思,但没有得到一个充满空值的列。至少,这是向前迈出的一步。在上面编辑。 你也是inner joining 三个表,没有左加入。如果您没有在查询中放置某种类型的过滤器,那么您将遇到大多数(所有)记录的笛卡尔积,这意味着您可能会进行全表扫描(慢,不是真的使用索引,因为没有理由)。您能否编辑您的问题以显示其中一些列的来源?例如,我们不知道best_model_fithoursabove4k_sunny 来自哪里。 @ps2goat,感谢有关笛卡尔查询的指针。我已更改为预期的左连接,设置了上面提到的索引广告,并处理了内存和缓存大小以响应注意到该进程是磁盘 io 绑定的。我仍在苦苦挣扎的是为什么 CASE 语句返回 null。 通常您指定一个else 语句。 CASE best_model_fit WHEN 'SUNNY' then dailywx.hoursabove4k_sunny ELSE -1 END applied_f_model_hours_above4k -- 在 else 子句中使用您想要的任何值作为默认值。如果它的所有值都是空的,那么您可能没有正确的查询的其余部分,或者数据没有按照您的想法设置(例如,它不符合您的条件。)***.com/q/40101963/2084315 【参考方案1】:

在一个表中,所有行都有相同的列。您不能拥有仅存在于某些行的列。由于查询结果本质上是一个表,因此也适用于那里。

因此,对于信息不适用的行,将结果设为 NULL 或 0 是您唯一的选择。

CASE 表达式返回 NULL 的原因是您没有 ELSE 分支。如果 WHEN 条件都不适用,则结果为 NULL。

查询的性能是另一回事。您需要提供EXPLAIN (ANALYZE, BUFFERS) 输出来分析它。但是在加入大表时,将work_mem 设置得足够高通常是有益的。

【讨论】:

感谢@Laurenz Albe。我现在在两个语句上都更改为左连接,并将我的内存/缓存值设置为这个过程相当高(26GB),并注意到查询的显着加速。但是,我仍然对 case 语句返回 null 的原因感到困惑。 我已经添加了解释。

以上是关于POSTGRESQL:使用连接表的案例的主要内容,如果未能解决你的问题,请参考以下文章

连接postgres特别消耗cpu资源而引发的PostgreSQL性能优化考虑

连接postgres特别消耗cpu资源而引发的PostgreSQL性能优化考虑

postgres数据库连接driver,url,username,password

Postgres 使用跨 2 个表的内部连接进行更新?

如何优化 Postgresql max_connections 和 node-postgres 连接池?

postgreSQL9.3版本安装好!pgadmin连接本机postgres数据库连接失败。。