首页 > 解决方案 > 从 CASE 语句中设置 PostgreSQL 变量

问题描述

目前使用 PostgresSQL 10 作为新手,并尽我所能遵循文档。欢迎大家帮忙。

我正在尝试根据 case 语句设置变量的值,以便可以在代码的下一部分中使用该值。我遇到了语法问题,老实说,我只是了解如何从 case 语句中设置值。

下面是我到目前为止的代码。

我正在尝试设置变量“AndSol”的值。根据案例陈述,该值将设置为 0 或 1。

带有注释“太阳辐射”的块是我在设置变量值时遇到问题的地方。其余代码仅供参考,以了解我想要实现的目标。我以THEN AndSol := 1;的方式结束每个 where 子句 ,我认为这就是错误所在。我不知道如何解决它。

基本流程:

  1. 确定变量应该是 0 还是 1。

  2. 设置变量。

  3. 在下一部分中使用该变量。

DO $$
DECLARE AndSol NUMERIC;
BEGIN
    DROP MATERIALIZED VIEW IF EXISTS view_6day_mat;
    CREATE MATERIALIZED VIEW view_6day_mat
    AS
        SELECT prod_qld_6km_grids.weather_cell_id,
                prod_qld_6km_grids.latitude,
                prod_qld_6km_grids.longitude,

               /* Solar Radiation */
                CASE
                    WHEN EXTRACT(MONTH FROM prod_weathergrids.dates) >= 8 AND EXTRACT(MONTH FROM prod_weathergrids.dates) <= 12 THEN AndSol := 1;
                    WHEN EXTRACT(MONTH FROM prod_weathergrids.dates) = 1 AND EXTRACT(MONTH FROM prod_weathergrids.dates) <= 2 AND prod_weathergrids.cloudcover < 30 then AndSol := 1;
                ELSE AndSol := 0; END/* 0 END AS AndersonsSolarRad, */

                /* Moisture Content */
                CASE WHEN prod_weathergrids.rh > 0 AND prod_weathergrids.temperature > 0 THEN
                    ROUND(4.37+0.161*prod_weathergrids.rh-0.1*(prod_weathergrids.temperature-25)-AndSol*0.027*prod_weathergrids.rh), 2)
                ELSE 0 END AS AndersonsHMC

                FROM MyTable
    ORDER BY prod_qld_6km_grids.weather_cell_id
END $$;

我从 pgAdmin 收到的错误消息是:

ERROR:  syntax error at or near ":="
LINE 49: ...(MONTH FROM prod_weathergrids.dates) <= 12 THEN AndSol := 1;
                                                                   ^
SQL state: 42601
Character: 2440

我必须承认,我不知道如何克服这个错误,因为我看到的文档和示例大多都使用“:=”设置变量。

标签: postgresqlplpgsql

解决方案


您正在使用 SQLCASE表达式。这个语句是有功能的。它会从一个值转换到第二个值,但它不能保存任何 PLpgSQL 语句。

PLpgSQL 支持CASE具有类似语法的过程,允许分配语句。但此语句不能嵌套在其他 SQL 语句中。

DO $$
DECLARE is_monday boolean;
BEGIN
  -- SQL case, functiona
  is_monday = CASE EXTRACT(DOW FROM CURRENT_DATE) 
                WHEN 1 THEN true -- only a value or SQL expression is allowed there 
                ELSE false 
              END;
  RAISE NOTICE 'Today is Monday %', is_monday;

  -- procedural PLpgSQL case
  -- cannot be used inside SQL statement
  CASE EXTRACT(DOW FROM CURRENT_DATE)
    WHEN 1 THEN
      -- nesting PLpgSQL statements
      is_monday := true;
      RAISE NOTICE 'today is Monday';
    ELSE
      is_monday := true;
      RAISE NOTICE 'today is Monday';
  END CASE; -- ending with "END CASE"
END; $$;

在 Postgres 中,你想要的是不可能的(不是没有相对丑陋的解决方法,不仅是 SQL)。当您计算列值时,您不能重复使用在同一级别计算的任何信息。

您可以使用派生表。您可以更深入地计算一些信息,并且可以在更高级别上更多次使用此信息:

SELECT dt.x, dt.x + 1, dt.x * 10
  FROM (SELECT random() * 10 AS x
          FROM generate_series(1, 10)) dt; -- derived table 

您的示例显示了有趣的错误 - 陷阱。您正在从 PLpgSQL 创建视图。但是这个视图将在没有 PLpgSQL 的情况下存在——所以你不能在那里使用 PLpgSQL 特性——比如变量。


推荐阅读