2016-07-13 4 views
0

Я только что закончил писать свою первую функцию PLSQL. Вот что он делает.Улучшение функции PL/pgSQL

Функция SQL пытается сбросить дублируемую временную метку до NULL.

  1. Из таблицы call_records найти всю временную метку, которые дублируются. (С использованием группы пути)
  2. цикла через каждый timestamp.Find все записи с такой же меткой времени (раз-1, так что только одна записью для данного времени является настоящее время)
  3. Из всех записей, найденных на шаге 2 обновление временной отметки в NULL

Вот как функция SQL выглядит.

CREATE OR REPLACE FUNCTION nullify() RETURNS INTEGER AS $$ 
DECLARE 
T call_records.timestamp%TYPE; 
-- Not sure why row_type does not work 
-- R call_records%ROWTYPE; 
S integer; 
CRNS bigint[]; 
TMPS bigint[]; 
sql_stmt varchar = ''; 
BEGIN 
FOR T,S IN (select timestamp,count(timestamp) as times from call_records where timestamp IS NOT NULL group by timestamp having count(timestamp) > 1) 
LOOP 
    sql_stmt := format('SELECT ARRAY(select plain_crn from call_records where timestamp=%s limit %s)',T,S-1); 
    EXECUTE sql_stmt INTO TMPS; 
    CRNS := array_cat(CRNS,TMPS); 
END LOOP; 

    sql_stmt = format('update call_records set timestamp=null where plain_crn in (%s)',array_to_string(CRNS,',')); 
    RAISE NOTICE '%',sql_stmt; 
    EXECUTE sql_stmt ; 
    RETURN 1; 
END 
$$ LANGUAGE plpgsql; 

Помогите мне лучше понять язык PL/pgSQL, предлагая мне, как это можно сделать лучше.

@a_horse_with_no_name: Здесь структура DB выглядит как \ d + call_records;

id integer primary key 
plain_crn bigint 
timestamp bigint 
efd  integer default 0 




    id | efd  | plain_crn | timestamp 
----------+------------+------------+----------- 
    1  | 2016062936 | 8777444059 | 14688250050095   
    2  | 2016062940 | 8777444080 | 14688250050095 
    3  | 2016063012 | 8880000000 | 14688250050020  
    4  | 2016043011 | 8000000000 | 14688240012012 
    5  | 2016013011 | 8000000001 | 14688250050020 
    6  | 2016022011 | 8440000001 | 

Теперь

select timestamp,count(timestamp) as times from call_records where timestamp IS NOT NULL group by timestamp having count(timestamp) > 1 

    timestamp  | count 
-----------------+----------- 
14688250050095 |  2 
14688250050020 |  2 

Все, что я хочу, чтобы обновить дубликат метки обнулить так, что только один из них запись имеет заданную отметку времени.

В коротком приведенном выше запросе должен возвращать результат, как это

select timestamp,count(timestamp) as times from call_records where timestamp IS NOT NULL group by timestamp; 

     timestamp  | count 
    -----------------+----------- 
    14688250050095 |  1 
    14688250050020 |  1 
+2

Здесь нет необходимости в динамическом SQL. Я не думаю, что вам нужна функция вообще, это звучит так, как будто это можно сделать с помощью одного оператора обновления. Но без полного определения таблицы и некоторых выборочных данных это почти невозможно сказать –

+0

@a_horse_with_no_name У меня есть вопрос. – Noobie

ответ

0

Вы можете использовать массив переменных напрямую (фильтр с предикатом =ANY() - с помощью динамического SQL является неправильным для этой цели:

 
postgres=# DO $$ 
DECLARE x int[] = '{1,2,3}'; 
result int[]; 
BEGIN 
    SELECT array_agg(v) 
    FROM generate_series(1,10) g(v) 
    WHERE v = ANY(x) 
    INTO result; 
    RAISE NOTICE 'result is: %', result; 
END; 
$$; 
NOTICE: result is: {1,2,3} 
DO 

Следующая - это типичная функция void - она ​​не возвращает никакого интересного. Обычно эти функции ничего не возвращают, когда все в порядке или возникает исключение. Возврат 1 RETURN 1 бесполезен.

CREATE OR REPLACE FUNCTION foo(par int) 
RETURNS void AS $$ 
BEGIN 
    IF EXISTS(SELECT * FROM footab WHERE id = par) 
    THEN 
    ... 
    ELSE 
    RAISE EXCEPTION 'Missing data for parameter: %', par; 
    END IF; 
END; 
$$ LANGUAGE plpgsql; 
+0

Какую переменную массива вы занимаете здесь? – Noobie

+0

x - переменная массива –