Хранимые процедуры
description
Transcript of Хранимые процедуры
![Page 1: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/1.jpg)
Хранимые процедуры
PL/plPgSQL
![Page 2: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/2.jpg)
Общий вид
[ DECLARE declarations ]BEGIN statementsEND
![Page 3: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/3.jpg)
ПримерCREATE FUNCTION somefunc() RETURNS integer AS $$<< outerblock >>DECLARE quantity integer := 30;BEGIN RAISE NOTICE 'Quantity here is %', quantity; -- Prints 30 quantity := 50; -- Create a subblock DECLARE quantity integer := 80; BEGIN RAISE NOTICE 'Quantity here is %', quantity; -- 80 RAISE NOTICE 'Outer quantity is %', outerblock.quantity; -- Prints 50 END; RAISE NOTICE 'Quantity here is %', quantity; -- Prints 50 RETURN quantity;END;$$ LANGUAGE plpgsql;
![Page 4: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/4.jpg)
Объявления
name [ CONSTANT ] type [ COLLATE collation_name ] [ NOT NULL ] [ { DEFAULT | := } expression ];
![Page 5: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/5.jpg)
Примеры объявлений
user_id integer;quantity numeric(5);url varchar;myrow tablename%ROWTYPE;myfield tablename.columnname%TYPE;
![Page 6: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/6.jpg)
Описание параметров процедур(1)
CREATE FUNCTION sales_tax(real) RETURNS real AS$$DECLARE subtotal ALIAS FOR $1;BEGIN RETURN subtotal * 0.06;END;$$ LANGUAGE plpgsql;
![Page 7: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/7.jpg)
Описание параметров процедур(2)
CREATE FUNCTION sales_tax(subtotal real) RETURNS real AS $$BEGIN RETURN subtotal * 0.06;END; $$ LANGUAGE plpgsql;
![Page 8: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/8.jpg)
Примеры процедурCREATE FUNCTION instr(varchar, integer) RETURNS integer AS$$DECLARE v_string ALIAS FOR $1; index ALIAS FOR $2;BEGIN -- some computations using v_string and index here END;$$ LANGUAGE plpgsql;
CREATE FUNCTION concat_selected_fields(in_t sometablename) RETURNS text AS$$BEGIN RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7;END;$$ LANGUAGE plpgsql;
![Page 9: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/9.jpg)
Выходные параметры
CREATE FUNCTION sum_n_product (x int, y int, OUT sum int, OUT prod int) AS$$BEGIN sum := x + y; prod := x * y;END;$$ LANGUAGE plpgsql;
![Page 10: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/10.jpg)
Операции(1)
Присваивание:tax := subtotal * 0.06; my_record.user_id := 20;Вызовы SQL ничего не возвращающие:
DELETE * FROM users WHERE id=userId;
Вызовы SQL возвращающие результат:PERFORM my_func('text', userId);
![Page 11: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/11.jpg)
Операции(2)
SELECT * INTO myrec FROM emp WHERE empname = myname;
IF NOT FOUND THEN RAISE EXCEPTION 'employee % not found', myname;END IF;
![Page 12: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/12.jpg)
Не делать ничего
BEGIN y := x / 0;EXCEPTION WHEN division_by_zero THEN NULL; -- ignore the errorEND;
BEGIN y := x / 0;EXCEPTION WHEN division_by_zero THEN -- ignore the errorEND;
![Page 13: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/13.jpg)
Управляющие структуры - RETURN
RETURN NEXT expression;RETURN QUERY query;RETURN QUERY EXECUTE command-string;
![Page 14: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/14.jpg)
Управляющие структуры - RETURNCREATE TABLE foo (fooid INT, foosubid INT, fooname TEXT);INSERT INTO foo VALUES (1, 2, 'three');INSERT INTO foo VALUES (4, 5, 'six');
CREATE OR REPLACE FUNCTION getAllFoo() RETURNS SETOF foo AS$BODY$DECLARE r foo%rowtype;BEGIN FOR r IN SELECT * FROM foo WHERE fooid > 0 LOOP -- can do some processing here RETURN NEXT r; -- return current row of SELECT END LOOP; RETURN;END$BODY$LANGUAGE 'plpgsql';
SELECT * FROM getallfoo();
![Page 15: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/15.jpg)
Управляющие структуры - IF, WHEN
IF ... THENIF ... THEN ... ELSEIF ... THEN ... ELSIF ... THEN ... ELSE
CASE ... WHEN ... THEN ... ELSE ... END CASECASE WHEN ... THEN ... ELSE ... END CASE
![Page 16: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/16.jpg)
Управляющие структуры - IF
IF v_user_id <> 0 THEN UPDATE users SET email = v_email WHERE user_id = v_user_id;END IF;
IF parentid IS NULL OR parentid = '' THEN RETURN fullname;ELSE RETURN hp_true_filename(parentid) || '/' || fullname;END IF;
![Page 17: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/17.jpg)
Управляющие структуры - IF
IF number = 0 THEN result := 'zero';ELSIF number > 0 THEN result := 'positive';ELSIF number < 0 THEN result := 'negative';ELSE -- hmm, the only other possibility -- is that number is null result := 'NULL';END IF;
![Page 18: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/18.jpg)
Управляющие структуры - WHEN
CASE x WHEN 1, 2 THEN msg := 'one or two';ELSE msg := 'other value than one or two';END CASE;
CASE WHEN x BETWEEN 0 AND 10 THEN msg := 'value is between zero and ten';WHEN x BETWEEN 11 AND 20 THEN msg := 'value is between eleven and twenty';END CASE;
![Page 19: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/19.jpg)
Циклы - LOOP
[ <<label>> ]LOOP statementsEND LOOP [ label ];
EXIT [ label ] [ WHEN boolean-expression ];CONTINUE [ label ] [ WHEN bool-expression ];
![Page 20: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/20.jpg)
LOOP - примеры
LOOP -- some computations IF count > 0 THEN EXIT; -- exit loop END IF;END LOOP;
LOOP -- some computationsEXIT WHEN count > 0; -- same result as previous exampleEND LOOP;
![Page 21: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/21.jpg)
LOOP - примеры
<<ablock>>BEGIN -- some computations IF stocks > 100000 THEN EXIT ablock; -- causes exit from the BEGIN block END IF; -- computations -- will be skipped when stocks > 100000END;
![Page 22: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/22.jpg)
LOOP - примеры
LOOP -- some computations EXIT WHEN count > 100; CONTINUE WHEN count < 50; -- some computations for -- count IN [50 .. 100]END LOOP;
![Page 23: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/23.jpg)
WHILE[ <<label>> ]WHILE boolean-expression LOOP statementsEND LOOP [ label ];WHILE amount_owed > 0 AND gift_certificate_balance > 0 LOOP -- some computations hereEND LOOP;
WHILE NOT done LOOP -- some computations hereEND LOOP;
![Page 24: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/24.jpg)
FOR - для числовых рядов
[ <<label>> ]FOR name IN [ REVERSE ] expression .. expression [ BY expression ] LOOP statementsEND LOOP [ label ];
FOR i IN REVERSE 10..1 BY 2 LOOP -- i will take on the values -- 10,8,6,4,2 within the loopEND LOOP;
![Page 25: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/25.jpg)
FOR - для запросов
[ <<label>> ]FOR target IN query LOOP statementsEND LOOP [ label ];
[ <<label>> ]FOR target IN EXECUTE text_expression [ USING expression [, ... ] ] LOOP statementsEND LOOP [ label ];
![Page 26: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/26.jpg)
FOR - для запросовCREATE FUNCTION cs_refresh_mviews() RETURNS integer AS$$DECLARE mviews RECORD;BEGIN RAISE NOTICE 'Refreshing materialized views...';
FOR mviews IN SELECT * FROM cs_materialized_views ORDER BY sort_key LOOP -- Now "mviews" has one record from cs_materialized_views RAISE NOTICE 'Refreshing materialized view %s ...', quote_ident(mviews.mv_name); EXECUTE 'TRUNCATE TABLE ' || quote_ident(mviews.mv_name); EXECUTE 'INSERT INTO ' || quote_ident(mviews.mv_name) || ' ' || mviews.mv_query; END LOOP;
RAISE NOTICE 'Done refreshing materialized views.'; RETURN 1;END;$$ LANGUAGE plpgsql;
![Page 27: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/27.jpg)
FOR - для массивов
[ <<label>> ]FOREACH target [ SLICE number ] IN ARRAY expression LOOP statementsEND LOOP [ label ];
![Page 28: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/28.jpg)
FOR - для массивов
CREATE FUNCTION sum(int[]) RETURNS int8 AS$$DECLARE s int8 := 0; x int;BEGIN FOREACH x IN ARRAY $1 LOOP s := s + x; END LOOP; RETURN s;END; $$ LANGUAGE plpgsql;
![Page 29: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/29.jpg)
FOR - для массивов
CREATE FUNCTION scan_rows(int[]) RETURNS void AS$$DECLARE x int[];BEGIN FOREACH x SLICE 1 IN ARRAY $1 LOOP RAISE NOTICE 'row = %', x; END LOOP;END; $$ LANGUAGE plpgsql;
SELECT scan_rows(ARRAY[[1,2,3],[4,5,6],[7,8,9],[10,11,12]]);NOTICE: row = {1,2,3}NOTICE: row = {4,5,6}NOTICE: row = {7,8,9}NOTICE: row = {10,11,12}
![Page 30: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/30.jpg)
Исключения
[ <<label>> ][ DECLARE declarations ]BEGIN statements EXCEPTION WHEN condition [ OR condition ... ] THEN statements [ WHEN condition [ OR condition ... ] THEN statements ... ]END;
![Page 31: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/31.jpg)
Исключения - пример
INSERT INTO mytab(firstname, lastname) VALUES('Tom', 'Jones');BEGIN UPDATE mytab SET firstname = 'Joe' WHERE lastname = 'Jones'; x := x + 1; y := x / 0;EXCEPTION WHEN division_by_zero THEN RAISE NOTICE 'caught division_by_zero'; RETURN x;END;
![Page 32: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/32.jpg)
Исключения - примерCREATE TABLE db (a INT PRIMARY KEY, b TEXT);CREATE FUNCTION merge_db(key INT, data TEXT) RETURNS VOID AS$$BEGIN LOOP -- first try to update the key UPDATE db SET b = data WHERE a = key; IF found THEN RETURN; END IF; -- not there, so try to insert the key -- if someone else inserts the same key concurrently, -- we could get a unique-key failure BEGIN INSERT INTO db(a,b) VALUES (key, data); RETURN; EXCEPTION WHEN unique_violation THEN -- Do nothing, and loop to try the UPDATE again. END; END LOOP;END;$$ LANGUAGE plpgsql;
SELECT merge_db(1, 'david'); SELECT merge_db(1, 'dennis');
![Page 33: Хранимые процедуры](https://reader035.fdocuments.in/reader035/viewer/2022070404/56813b00550346895da39e18/html5/thumbnails/33.jpg)
Анализ исключенийDECLARE text_var1 text; text_var2 text; text_var3 text;BEGIN -- some processing which might cause an exception ...EXCEPTION WHEN OTHERS THEN GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT, text_var2 = PG_EXCEPTION_DETAIL, text_var3 = PG_EXCEPTION_HINT;END;