Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita294726

Browse files
committed
Incorporate examples and doc patches from Mark Kirkwood and David Fetter.
1 parent29e5833 commita294726

File tree

3 files changed

+203
-5
lines changed

3 files changed

+203
-5
lines changed

‎doc/src/sgml/plpgsql.sgml

Lines changed: 180 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.55 2005/01/08 22:13:34 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.56 2005/01/14 01:16:22 tgl Exp $
33
-->
44

55
<chapter id="plpgsql">
@@ -2304,6 +2304,32 @@ SELECT reffunc2();
23042304

23052305
FETCH ALL IN "&lt;unnamed cursor 1&gt;";
23062306
COMMIT;
2307+
</programlisting>
2308+
</para>
2309+
2310+
<para>
2311+
The following example shows one way to return multiple cursors
2312+
from a single function:
2313+
2314+
<programlisting>
2315+
CREATE FUNCTION myfunc(refcursor, refcursor) RETURNS SETOF refcursor AS $$
2316+
BEGIN
2317+
OPEN $1 FOR SELECT * FROM table_1;
2318+
RETURN NEXT $1;
2319+
OPEN $2 FOR SELECT * FROM table_2;
2320+
RETURN NEXT $2;
2321+
RETURN;
2322+
END;
2323+
$$ LANGUAGE plpgsql;
2324+
2325+
-- need to be in a transaction to use cursors.
2326+
BEGIN;
2327+
2328+
SELECT * FROM myfunc('a', 'b');
2329+
2330+
FETCH ALL FROM a;
2331+
FETCH ALL FROM b;
2332+
COMMIT;
23072333
</programlisting>
23082334
</para>
23092335
</sect3>
@@ -2585,8 +2611,6 @@ $emp_stamp$ LANGUAGE plpgsql;
25852611
CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
25862612
FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
25872613
</programlisting>
2588-
2589-
25902614
</example>
25912615

25922616
<para>
@@ -2646,6 +2670,159 @@ AFTER INSERT OR UPDATE OR DELETE ON emp
26462670
FOR EACH ROW EXECUTE PROCEDURE process_emp_audit();
26472671
</programlisting>
26482672
</example>
2673+
2674+
<para>
2675+
One use of triggers is to maintain a summary table
2676+
of another table. The resulting summary can be used in place of the
2677+
original table for certain queries &mdash; often with vastly reduced run
2678+
times.
2679+
This technique is commonly used in Data Warehousing, where the tables
2680+
of measured or observed data (called fact tables) can be extremely large.
2681+
<xref linkend="plpgsql-trigger-summary-example"> shows an example of a
2682+
trigger procedure in <application>PL/pgSQL</application> that maintains
2683+
a summary table for a fact table in a data warehouse.
2684+
</para>
2685+
2686+
2687+
<example id="plpgsql-trigger-summary-example">
2688+
<title>A <application>PL/pgSQL</application> Trigger Procedure For Maintaining A Summary Table</title>
2689+
2690+
<para>
2691+
The schema detailed here is partly based on the <emphasis>Grocery Store
2692+
</emphasis> example from <emphasis>The Data Warehouse Toolkit</emphasis>
2693+
by Ralph Kimball.
2694+
</para>
2695+
2696+
<programlisting>
2697+
--
2698+
-- Main tables - time dimension and sales fact.
2699+
--
2700+
CREATE TABLE time_dimension (
2701+
time_key integer NOT NULL,
2702+
day_of_week integer NOT NULL,
2703+
day_of_month integer NOT NULL,
2704+
month integer NOT NULL,
2705+
quarter integer NOT NULL,
2706+
year integer NOT NULL
2707+
);
2708+
CREATE UNIQUE INDEX time_dimension_key ON time_dimension(time_key);
2709+
2710+
CREATE TABLE sales_fact (
2711+
time_key integer NOT NULL,
2712+
product_key integer NOT NULL,
2713+
store_key integer NOT NULL,
2714+
amount_sold numeric(12,2) NOT NULL,
2715+
units_sold integer NOT NULL,
2716+
amount_cost numeric(12,2) NOT NULL
2717+
);
2718+
CREATE INDEX sales_fact_time ON sales_fact(time_key);
2719+
2720+
--
2721+
-- Summary table - sales by time.
2722+
--
2723+
CREATE TABLE sales_summary_bytime (
2724+
time_key integer NOT NULL,
2725+
amount_sold numeric(15,2) NOT NULL,
2726+
units_sold numeric(12) NOT NULL,
2727+
amount_cost numeric(15,2) NOT NULL
2728+
);
2729+
CREATE UNIQUE INDEX sales_summary_bytime_key ON sales_summary_bytime(time_key);
2730+
2731+
--
2732+
-- Function and trigger to amend summarized column(s) on UPDATE, INSERT, DELETE.
2733+
--
2734+
CREATE OR REPLACE FUNCTION maint_sales_summary_bytime() RETURNS TRIGGER AS $maint_sales_summary_bytime$
2735+
DECLARE
2736+
delta_time_key integer;
2737+
delta_amount_sold numeric(15,2);
2738+
delta_units_sold numeric(12);
2739+
delta_amount_cost numeric(15,2);
2740+
BEGIN
2741+
2742+
-- Work out the increment/decrement amount(s).
2743+
IF (TG_OP = 'DELETE') THEN
2744+
2745+
delta_time_key = OLD.time_key;
2746+
delta_amount_sold = -1 * OLD.amount_sold;
2747+
delta_units_sold = -1 * OLD.units_sold;
2748+
delta_amount_cost = -1 * OLD.amount_cost;
2749+
2750+
ELSIF (TG_OP = 'UPDATE') THEN
2751+
2752+
-- forbid updates that change the time_key -
2753+
-- (probably not too onerous, as DELETE + INSERT is how most
2754+
-- changes will be made).
2755+
IF ( OLD.time_key != NEW.time_key) THEN
2756+
RAISE EXCEPTION 'Update of time_key : % -&gt; % not allowed', OLD.time_key, NEW.time_key;
2757+
END IF;
2758+
2759+
delta_time_key = OLD.time_key;
2760+
delta_amount_sold = NEW.amount_sold - OLD.amount_sold;
2761+
delta_units_sold = NEW.units_sold - OLD.units_sold;
2762+
delta_amount_cost = NEW.amount_cost - OLD.amount_cost;
2763+
2764+
ELSIF (TG_OP = 'INSERT') THEN
2765+
2766+
delta_time_key = NEW.time_key;
2767+
delta_amount_sold = NEW.amount_sold;
2768+
delta_units_sold = NEW.units_sold;
2769+
delta_amount_cost = NEW.amount_cost;
2770+
2771+
END IF;
2772+
2773+
2774+
-- Update the summary row with the new values.
2775+
UPDATE sales_summary_bytime
2776+
SET amount_sold = amount_sold + delta_amount_sold,
2777+
units_sold = units_sold + delta_units_sold,
2778+
amount_cost = amount_cost + delta_amount_cost
2779+
WHERE time_key = delta_time_key;
2780+
2781+
2782+
-- There might have been no row with this time_key (e.g new data!).
2783+
IF (NOT FOUND) THEN
2784+
BEGIN
2785+
INSERT INTO sales_summary_bytime (
2786+
time_key,
2787+
amount_sold,
2788+
units_sold,
2789+
amount_cost)
2790+
SELECT f.time_key,
2791+
sum(f.amount_sold),
2792+
sum(f.units_sold),
2793+
sum(f.amount_cost)
2794+
FROM sales_fact f
2795+
WHERE f.time_key = delta_time_key
2796+
GROUP BY f.time_key;
2797+
-- This query can potentially be very expensive if the trigger
2798+
-- is created on sales_fact without the time_key indexes.
2799+
-- Some care is needed to ensure that this situation does
2800+
-- *not* occur.
2801+
EXCEPTION
2802+
--
2803+
-- Catch race condition when two transactions are adding data
2804+
-- for a new time_key.
2805+
--
2806+
WHEN UNIQUE_VIOLATION THEN
2807+
UPDATE sales_summary_bytime
2808+
SET amount_sold = amount_sold + delta_amount_sold,
2809+
units_sold = units_sold + delta_units_sold,
2810+
amount_cost = amount_cost + delta_amount_cost
2811+
WHERE time_key = delta_time_key;
2812+
2813+
END;
2814+
END IF;
2815+
RETURN NULL;
2816+
2817+
END;
2818+
$maint_sales_summary_bytime$ LANGUAGE plpgsql;
2819+
2820+
CREATE TRIGGER maint_sales_summary_bytime
2821+
AFTER INSERT OR UPDATE OR DELETE ON sales_fact
2822+
FOR EACH ROW EXECUTE PROCEDURE maint_sales_summary_bytime();
2823+
</programlisting>
2824+
</example>
2825+
26492826
</sect1>
26502827

26512828
<!-- **** Porting from Oracle PL/SQL **** -->

‎doc/src/sgml/ref/alter_table.sgml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.76 2005/01/10 00:04:43 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.77 2005/01/14 01:16:52 tgl Exp $
33
PostgreSQL documentation
44
-->
55

@@ -537,6 +537,17 @@ ALTER TABLE distributors
537537
</programlisting>
538538
</para>
539539

540+
<para>
541+
To change an integer column containing UNIX timestamps to <type>timestamp
542+
with time zone</type> via a <literal>USING</literal> clause:
543+
<programlisting>
544+
ALTER TABLE foo
545+
ALTER COLUMN foo_timestamp TYPE timestamp with time zone
546+
USING
547+
timestamp with time zone 'epoch' + foo_timestamp * interval '1 second';
548+
</programlisting>
549+
</para>
550+
540551
<para>
541552
To rename an existing column:
542553
<programlisting>

‎doc/src/sgml/ref/create_opclass.sgml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/ref/create_opclass.sgml,v 1.12 2003/11/29 19:51:38 pgsql Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/ref/create_opclass.sgml,v 1.13 2005/01/14 01:16:52 tgl Exp $
33
PostgreSQL documentation
44
-->
55

@@ -205,6 +205,16 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
205205
</para>
206206
</refsect1>
207207

208+
<refsect1>
209+
<title>Notes</title>
210+
211+
<para>
212+
The operators should not be defined by SQL functions. A SQL function
213+
is likely to be inlined into the calling query, which will prevent
214+
the optimizer from recognizing that the query matches an index.
215+
</para>
216+
</refsect1>
217+
208218
<refsect1>
209219
<title>Examples</title>
210220

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp