简体   繁体   中英

PG Rule - Using NEW in subquery

I have a rule that runs on update to a source table. The rule queries data across multiple other tables, formats the data, and inserts it into another transform table. Here is an example of what I have so far.

CREATE OR REPLACE RULE
  value_insert

AS ON UPDATE TO
  source_table

DO ALSO INSERT INTO transform_table(
  username
  ,status
  ,section
  )
SELECT
  username
  ,MAX(status)
  ,MAX(section)
FROM
(
SELECT 
  username
  ,CASE
    WHEN item = status
    THEN value
    ELSE NULL
  END AS status
  ,CASE
    WHEN item = section
    THEN value
    ELSE NULL
  END AS section
FROM
(
SELECT
  username
  ,item
  ,value
FROM
  table1
  ,table2
WHERE
  item = status
  OR item = section
  AND source_table.username = NEW.username
)
)
GROUP BY
  username

I am trying to pass the NEW value into the subquery, but I receive the error "ERROR: subquery in FROM cannot refer to other relations of same query level". Using NEW in the outermost where statement works, but the query take a long time due to the large amount of data in the tables.

Is it possible to pass the NEW value into the subquery of this rule? I am using PG 8.3 and PGAdmin 1.12

Solved this by implementing a trigger function. As far as I can tell, you cannot pass the NEW value to a subquery in a rule (PG 8.3).

The script below will collect only data from table1 and table2 that corresponds to updated record in old_table, reformat the data, and insert it into new_table. By switching to a trigger and inserting the argument into the base query, the processing time has dropped from ~2 seconds to ~50 ms.

The function:

CREATE OR REPLACE FUNCTION get_data()
RETURNS TRIGGER AS $$

BEGIN

INSERT INTO new_table(
  username
  ,status
  ,section
  )
SELECT
  username
  ,MAX(status)
  ,MAX(section)
FROM
(
SELECT 
  username
  ,CASE
    WHEN item = status
    THEN value
    ELSE NULL
  END AS status
  ,CASE
    WHEN item = section
    THEN value
    ELSE NULL
  END AS section
FROM
(
SELECT
  username
  ,item
  ,value
FROM
  table1
  ,table2
WHERE
  (item = status OR item = section)
  AND table1.username = table2.username
  AND table2.username = old_table.username
  AND old_table.username = NEW.username
)
)
GROUP BY
  username;

RETURN NEW;

END;

$$

LANGUAGE plpgSQL;

The trigger:

CREATE TRIGGER
  old_table_trigger

BEFORE UPDATE ON
  old_table

FOR EACH ROW EXECUTE PROCEDURE get_data();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM