Установка переменной PostgreSQL изнутри оператора CASE - PullRequest
0 голосов
/ 30 сентября 2019

В настоящее время я использую PostgresSQL 10 в качестве новичка и, как могу, следую документации. Вся помощь приветствуется.

Я пытаюсь установить значение переменной на основе оператора case, чтобы я мог использовать это значение в следующей части моего кода. У меня проблемы с синтаксисом, и, честно говоря, я просто понимаю, как установить значение из оператора case.

Ниже приведен код, который я получил до сих пор.

Я пытаюсь установить значение переменной "AndSol". Значение будет либо установлено на 0, либо на 1 в зависимости от ситуации.

В блоке с комментарием «Солнечное излучение» у меня возникают проблемы при установке значения переменной. Остальная часть кода включена только для справки о том, чего я пытаюсь достичь. Я заканчиваю каждое предложение where чем-то вроде THEN AndSol: = 1; , и я предполагаю, что именно в этом и заключается ошибка. Я не знаю, как это исправить.

Основной поток:

  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

Я должен признать, я не знаю, как преодолеть ошибку, потому что из документации и примеров, которые я видел, в основном все устанавливают переменную, используя ": =".

1 Ответ

1 голос
/ 30 сентября 2019

Вы используете выражение SQL CASE. Это утверждение является функциональным . Он выполняет преобразование из одного значения в второе, но не может содержать какие-либо операторы 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; $$;

То, что вы хотите, невозможно (без относительного уродливого обходного пути и не только с SQL) в Postgres. Когда вы вычисляете значение столбца, вы не можете повторно использовать любую информацию, рассчитанную на том же уровне.

Вы можете использовать производные таблицы. Вы можете вычислить некоторую информацию глубже, и вы можете использовать эту информацию больше раз на более высоких уровнях:

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 - например, переменные.

...