2017-01-25 14 views
0

Я создаю хранимую процедуру для репликации вывода запроса, найденного в файле карты на нашем сервере карт.Возврат таблицы с хранимой процедурой plpgsql

Запрос:

select g.gid, g.geom, g.basin, a.\"DATE\", a.\"VALUE\" 
from sarffg_basins_00_regional_3sec as g 
    join \"%prod_table%\" as a on g.basin = a.\"BASIN\" 
where a.\"DATE\" = '%prod_date%' 

Я не могу отправить вывод в целом из-за SO размещать ограничения длины, но важно то, что этот запрос дает мне мой вывод с именами столбцов. Регулировка синтаксиса, чтобы соответствовать обычной SQL для запуска внутри SQL-оболочки:

select g.gid, 
     g.geom, 
     g.basin, 
     a."DATE", 
     a."VALUE" from sarffg_basins_00_regional_3sec 
     as g 
     join "FFGS_PROCESSED_PRODUCT_ASM_SACSMA_UPPER_BASIN_TIMESERIES" 
     as a on g.basin = a."BASIN" where a."DATE" = '2017-01-12 18:00:00+00'; 

дает столбцы

gid  | geom  |  basin  |   DATE   | VALUE 

Моя хранимая процедура имеет следующий обратный заголовок:

RETURNS table (
    gid integer, 
    geom geometry(MultiPolygon,4326), 
    basin double precision, 
    date timestamptz, 
    value double precision 
    ) 

И с возвратом:

RETURN QUERY 
    EXECUTE 'SELECT g.'||quote_ident('gid')||', 
        g.'||quote_ident('geom')||', 
        g.'||quote_ident('basin')||', 
        a.'||quote_ident('DATE')||', 
        a.'||quote_ident('VALUE')||' 
        FROM sarffg_basins_00_regional_3sec AS g JOIN '||quote_ident(prod_table)||' AS a 
        ON g.'||quote_ident('basin')||' = a.'||quote_ident('BASIN')||' 
        WHERE a.'||quote_ident('DATE')||' = '''||adj_timestamp||''''; 

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

Query error. Error executing query: ERROR: column "VALUE" does not exist 
LINE 1: select "VALUE",encode(ST_AsBinary(ST_Force2D("geom"),'NDR'),... 

Я знаю, что колонка «VALUE» существует в prod_table, особенно принимая во внимание эту функцию отлично работает при вызове в Psql оболочки.

Что мне нужно сделать, чтобы мои выходные данные имели заголовки столбцов?

EDIT: немного больше контекста на файле карты.

Весь запрос в файле проекта заключается в следующем:

geom from (select g.gid, g.geom, g.basin, a.\"DATE\", a.\"VALUE\" from sarffg_basins_00_regional_3sec as g join \"%prod_table%\" as a on g.basin = a.\"BASIN\" where a.\"DATE\" = '%prod_date%') as subquery using unique gid using srid=4326 

я в основном нужно повторить эту функцию с помощью хранимой процедуры, либо в его полностью или только подзапроса. Мои различные попытки можно найти здесь: Syntax error at or near "USING". Кажется, я пришел ближе с попыткой повторить только подзапроса - т.е.

geom from (select * from ingest_ffgs_prod_composite_csv('%prod_table%', 1484438400)) as subquery using unique gid using srid=4326 

EDIT 2: Теперь, когда я провел больше времени, думая об этом, я не знаю, почему «VALUE» будет недостающее столбец, когда запрос выбирает только «geom» из подзапроса, возвращаемого из моей хранимой процедуры. Возможно, это не причина ошибки в конце концов.

РЕДАКТИРОВАТЬ 3: В соответствии с запросом здесь представлена ​​вся функция.

CREATE OR REPLACE FUNCTION ingest_ffgs_prod_composite_csv(prod_table text, epoch_seconds bigint, original boolean DEFAULT false, roll_back boolean DEFAULT true) 
RETURNS table (
    gid integer, 
    geom geometry(MultiPolygon,4326), 
    basin double precision, 
    date timestamptz, 
    VALUE double precision 
    ) 
AS $$ 
DECLARE 
    c01n text := 'BASIN';   c01t text := 'double precision'; 
    c02n text := 'MAP01';   c02t text := 'double precision'; 
    c03n text := 'MAP03';   c03t text := 'double precision'; 
    c04n text := 'MAP06';   c04t text := 'double precision'; 
    c05n text := 'MAP24';   c05t text := 'double precision'; 
    c06n text := 'GMAP06';   c06t text := 'double precision'; 
    c07n text := 'GMAP24';   c07t text := 'double precision'; 
    c08n text := 'ASMU06';   c08t text := 'double precision'; 
    c09n text := 'ASML06';   c09t text := 'double precision'; 
    c10n text := 'ASMT06';   c10t text := 'double precision'; 
    c11n text := 'FFG01';   c11t text := 'double precision'; 
    c12n text := 'FFG03';   c12t text := 'double precision'; 
    c13n text := 'FFG06';   c13t text := 'double precision'; 
    c14n text := 'PREVFFG01';  c14t text := 'double precision'; 
    c15n text := 'PREVFFG03';  c15t text := 'double precision'; 
    c16n text := 'PREVFFG06';  c16t text := 'double precision'; 
    c17n text := 'FMAP01';   c17t text := 'double precision'; 
    c18n text := 'FMAP03';   c18t text := 'double precision'; 
    c19n text := 'FMAP06';   c19t text := 'double precision'; 
    c20n text := 'IFFT01';   c20t text := 'double precision'; 
    c21n text := 'IFFT03';   c21t text := 'double precision'; 
    c22n text := 'IFFT06';   c22t text := 'double precision'; 
    c23n text := 'PFFT01';   c23t text := 'double precision'; 
    c24n text := 'PFFT03';   c24t text := 'double precision'; 
    c25n text := 'PFFT06';   c25t text := 'double precision'; 
    c26n text := 'FFFT01';   c26t text := 'double precision'; 
    c27n text := 'FFFT03';   c27t text := 'double precision'; 
    c28n text := 'FFFT06';   c28t text := 'double precision'; 
    c29n text := 'PET06';   c29t text := 'double precision'; 
    tablename_csv text := 'temp_table_csv'; 
    tablename_ts text := 'temp_table_ts'; 
    tablename_ret text := 'temp_table_ret'; 
    full_timestamp timestamptz; 
    adj_timestamp_text text; 
    adj_timestamp timestamptz; 
    year double precision; 
    month double precision; 
    day double precision; 
    hour double precision; 
    year_text text; 
    month_text text; 
    day_text text; 
    hour_text text; 
    csv_base_path text; 
    csv_filename text; 
    csv_file_full_path text; 
    ret_rec record; 
    product text; 
    interval text; 
    curr_basin int; 
    curr_val double precision; 
    rec record; 
    existing_table boolean; 
    existing_data boolean := false; 
    ret_geom geometry(MultiPolygon,4326); 
BEGIN 
    -- parse prod_table name to determine which product and time interval we need to build a timeseries for 
    ------------------------------------------------------------------------------------------------------- 
    product := split_part(prod_table, '_', 4); 
    interval := rtrim(split_part(prod_table, '_', 6), 'HR'); 
    IF interval = 'UPPE' THEN -- asm interval reads as 'UPPE'. Default to 6 hours 
      interval := '06'; 
    END IF; 

    raise notice 'product: %', product; 
    raise notice 'interval: %', interval; 

    -- convert epoch seconds to timestamp for parsing 
    ------------------------------------------------- 
    full_timestamp := to_timestamp(epoch_seconds); 
    year := date_part('year', full_timestamp); 
    month := date_part('month', full_timestamp); 
    day := date_part('day', full_timestamp); 

    IF roll_back THEN 
      hour := date_part('hour', full_timestamp) - (date_part('hour', full_timestamp)::integer % interval::int); 
    ELSE 
      hour := date_part('hour', full_timestamp); 
    END IF; 

    year_text := year; 
    month_text := month; 
    day_text := day; 
    hour_text := hour; 

    IF month < 10 THEN 
      month_text := '0' || month; 
    END IF; 
    IF day < 10 THEN 
      day_text := '0' || day; 
    END IF; 
    IF hour < 10 THEN 
      hour_text := '0' || hour; 
    END IF; 

    adj_timestamp_text := year_text || '-' || month_text || '-' || day_text || ' ' || hour_text || ':00:00+00'; 
    adj_timestamp := adj_timestamp_text::timestamptz; 

    raise notice 'year: %', year_text; 
    raise notice 'month: %', month_text; 
    raise notice 'day: %', day_text; 
    raise notice 'hour: %', hour_text; 

    -- check if table with the desired data already exists within the database 
    -------------------------------------------------------------------------- 
    EXECUTE format('SELECT EXISTS (
          SELECT 1 
          FROM pg_tables 
          WHERE schemaname = ''public'' 
          AND tablename = '''||prod_table||''')') INTO existing_table; 

    IF existing_table THEN 
      EXECUTE format('SELECT EXISTS (
            SELECT 1 
            FROM '||quote_ident(prod_table)||' 
            WHERE '||quote_ident('DATE')||' = '''||adj_timestamp||''')') INTO existing_data; 
    END IF; 

    raise notice 'existing_table: %', existing_table; 
    raise notice 'existing_data: %', existing_data; 





    IF NOT existing_data THEN -- need to manually create tables from csv file 

      -- construct full path to csv file 
      ---------------------------------- 
      csv_base_path := '/SARFFG/EXP/DATA/EXPORTS/REGIONAL/'||year_text||'/'||month_text||'/'||day_text||'/COMPOSITE_CSV'; 

      IF original THEN 
        csv_filename := year_text||month_text||day_text||'-'||hour_text||'00_ffgs_prod_composite_table_01hr_regional_original.csv'; 
      ELSE 
        csv_filename := year_text||month_text||day_text||'-'||hour_text||'00_ffgs_prod_composite_table_01hr_regional.csv'; 
      END IF; 

      csv_file_full_path := csv_base_path||'/'||csv_filename; 
           ----------------------------------------------- 
      raise notice 'csv file: %', csv_file_full_path; 

      -- create temporary table to store CSV contents 
      ----------------------------------------------- 
      EXECUTE format('CREATE TEMP TABLE '||tablename_csv||' ('||c01n||' '||c01t||', 
                   '||c02n||' '||c02t||', 
                   '||c03n||' '||c03t||', 
                   '||c04n||' '||c04t||', 
                   '||c05n||' '||c05t||', 
                   '||c06n||' '||c06t||', 
                   '||c07n||' '||c07t||', 
                   '||c08n||' '||c08t||', 
                   '||c09n||' '||c09t||', 
                   '||c10n||' '||c10t||', 
                   '||c11n||' '||c11t||', 
                   '||c12n||' '||c12t||', 
                   '||c13n||' '||c13t||', 
                   '||c14n||' '||c14t||', 
                   '||c15n||' '||c15t||', 
                   '||c16n||' '||c16t||', 
                   '||c17n||' '||c17t||', 
                   '||c18n||' '||c18t||', 
                   '||c19n||' '||c19t||', 
                   '||c20n||' '||c20t||', 
                   '||c21n||' '||c21t||', 
                   '||c22n||' '||c22t||', 
                   '||c23n||' '||c23t||', 
                   '||c24n||' '||c24t||', 
                   '||c25n||' '||c25t||', 
                   '||c26n||' '||c26t||', 
                   '||c27n||' '||c27t||', 
                   '||c28n||' '||c28t||', 
                   '||c29n||' '||c29t||') ON COMMIT DROP'); 

      EXECUTE format('COPY '||tablename_csv||' FROM '''||csv_file_full_path||''' DELIMITER '','' CSV HEADER'); 



      -- create temp timeseries table 
      ------------------------------- 
      EXECUTE format('CREATE TEMP TABLE '||tablename_ts||' (date timestamptz, basin int, value double precision) ON COMMIT DROP'); 

      FOR rec in SELECT * FROM temp_table_csv 
      LOOP 
        curr_basin := rec.basin; 
        IF product = 'MAP' THEN 
          IF interval = '01' THEN 
            curr_val := rec.map01; 
          ELSIF interval = '03' THEN 
            curr_val := rec.map03; 
          ELSIF interval = '06' THEN 
            curr_val := rec.map06; 
          ELSIF interval = '24' THEN 
            curr_val := rec.map24; 
          ELSE 
            raise warning 'interval not found'; 
            EXIT; 
          END IF; 
        ELSIF product = 'ASM' THEN 
          IF interval = '06' THEN 
            curr_val := rec.asmu06; 
          ELSE 
            raise warning 'interval not found'; 
            EXIT; 
          END IF; 
        ELSIF product = 'FFG' THEN 
          IF interval = '01' THEN 
            curr_val := rec.ffg01; 
          ELSIF interval = '03' THEN 
            curr_val := rec.ffg03; 
          ELSIF interval = '06' THEN 
            curr_val := rec.ffg06; 
          ELSE 
            raise warning 'interval not found'; 
            EXIT; 
          END IF; 
        ELSIF product = 'FFT' THEN 
          IF interval = '01' THEN 
            curr_val := rec.fft01; 
          ELSIF interval = '03' THEN 
            curr_val := rec.fft03; 
          ELSIF interval = '06' THEN 
            curr_val := rec.fft06; 
          ELSE 
            raise warning 'interval not found'; 
            EXIT; 
          END IF; 
        ELSE 
          raise warning 'product not found'; 
          EXIT; 
        END IF; 

        INSERT INTO temp_table_ts (date, basin, value) VALUES (adj_timestamp, curr_basin, curr_val); 
      END LOOP; 

      RETURN QUERY 
      EXECUTE 'SELECT g.gid, 
          g.geom, 
          g.basin, 
          a.date, 
          a.value 
          FROM sarffg_basins_00_regional_3sec 
          AS g 
          JOIN '||tablename_ts||' 
          AS a 
          ON g.'||quote_ident('basin')||' = a.'||quote_ident('basin')||' 
          WHERE a.'||quote_ident('date')||' = '''||adj_timestamp||''''; 
    ELSE 

      RETURN QUERY 
      EXECUTE format('SELECT g.gid, 
            g.geom, 
            g.basin, 
            a."DATE", 
            a."VALUE" 
            FROM sarffg_basins_00_regional_3sec AS g 
            JOIN %I AS a ON g.basin = a."BASIN" 
            WHERE a."DATE" = $1', prod_table) 
            using adj_timestamp; 

    END IF; 

END; 
$$ LANGUAGE plpgsql; 

EDIT 4: После того, как какой-то более должной осмотрительности, я вернулся к мысли вопрос приходит из-за отсутствия имен столбцов в моем выходе. Мои значения colorscales явно указывают «VALUE», но, очевидно, без имен столбцов он не знает, какой из них «VALUE».

Изменение моего запроса

select gid, geom, basin, "DATE", "VALUE" from ingest_ffgs_prod_composite_csv('%prod_table%', 1484438400) 

дает мне мои имена столбцов, но не решить мою проблему, к сожалению.

+0

SQL, в файле проекта работает как есть, единственное объяснение, у меня есть для этого является то, что mapfiles не использовать обычный синтаксис SQL. Запрос, который я запускал в оболочке sql для соответствия запросу mapfile: «select g.gid, g.geom, g.basin, a.» DATE », a.« VALUE »из sarffg_basins_00_regional_3sec, поскольку g присоединяется к« FFGS_PROCESSED_PRODUCT_ASM_SACSMA_UPPER_BASIN_TIMESERIES »в качестве на g.basin = a. "BASIN" где a. "DATE" = '2017-01-12 18: 00: 00 + 00'; ' –

+0

Я думаю, что этот вопрос является дубликатом этого http: // stackoverflow. com/questions/41842492/syntax-error-at-or-near-using? noredirect = 1 # comment70881921_41842492, который уже принял ответ –

ответ

1

Ваш вопрос слишком запутан. Тем не менее, я заметил проблемы с идентификаторами . Функция заявляет возвращаемый тип:

... 
RETURNS table (
    ... 
    date timestamptz, 
    VALUE double precision 
    ) 
...

Но вызов функции не соответствует:

select gid, geom, basin, "DATE", "VALUE" from ingest_ffgs_prod_composite_csv(...

Это объясняет ваше сообщение об ошибке отлично:

ERROR: column "VALUE" does not exist 

Поскольку нет колонки "VALUE". Только value (двойные или нет).

Все неупомянутые идентификаторы передаются в нижний регистр в Postgres. Так VALUE и value (но не "VALUE" или "Value") являются идентичными как идентификаторы. Но не как струны. При переходе на quote_ident() или format() с номером '%I', случай значителен, так как он экранирован. Итак:

a.'||quote_ident('DATE')||', 
a.'||quote_ident('VALUE')||' 

производит a."DATE", a."VALUE", который отличается от a.DATE, a.VALUE.

Кроме того, названия столбцов в теле функции PL/pgSQL или SQL не видны снаружи. Для вызова функции используется только заявленный тип возврата.

Я бы рекомендовал в качестве имен столбцов date или value. Both are allowed in Postgres, but reserved words in standard SQL.

Используйте только юридические, строчные, некотируемые идентификаторы исключительно, чтобы избежать такой путаницы.

+0

Спасибо за помощь Эрвина. Ваши ответы всегда очень информативны. Моя проблема закончилась тем, что вы предложили - неправильное цитирование для обработки чувствительности к регистру. Изменение моего оператора return на «VALUE» позволило моему файлу map правильно идентифицировать возвращаемый столбец –