从 CASE 语句内部设置 PostgreSQL 变量

ana*_*ine 4 postgresql plpgsql

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

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

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

我正在尝试设置变量“AndSol”的值。根据 case 语句,该值将设置为 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 $$;
Run Code Online (Sandbox Code Playgroud)

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

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

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

Pav*_*ule 8

您正在使用 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 := false;
      RAISE NOTICE 'today is not Monday';
  END CASE; -- ending with "END CASE"
END; $$;
Run Code Online (Sandbox Code Playgroud)

在 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 
Run Code Online (Sandbox Code Playgroud)

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