2016-11-18 1 views
0

J'essaie d'utiliser SQL dynamique avec Postgresql. Je suis coincé avec essayer d'utiliser le champ id de db_row RECORD dans une autre instruction EXECUTE. Champ id est défini dans la variable d'enregistrement mais je reçois toujours l'erreur:postgresql, impossible d'identifier la colonne dans le type de données d'enregistrement

ERROR: could not identify column "id" in record data type 
LINE 1: SELECT $1.id FROM audit.portfolio WHERE alter_type = 'INSERT... 
      ^
QUERY: SELECT $1.id FROM audit.portfolio WHERE alter_type = 'INSERT' AND id = $1.id 
CONTEXT: PL/pgSQL function inline_code_block line 14 at EXECUTE 

Ce sont mes données et fonction de test:

CREATE TABLE IF NOT EXISTS public.portfolio 
(
    id INTEGER NOT NULL, 
    name CHARACTER VARYING, 
    CONSTRAINT portfolio_pkey PRIMARY KEY (id) 
) 
WITH (OIDS = FALSE); 

CREATE TABLE IF NOT EXISTS audit.portfolio 
(
    alter_type TEXT, 
    id   INTEGER NOT NULL, 
    name  CHARACTER VARYING, 
    CONSTRAINT portfolio_pkey PRIMARY KEY (id) 
) 
WITH (OIDS = FALSE 
); 

INSERT INTO public.portfolio (id, name) VALUES (1, 'NAME 1'), (2, 'NAME 2'); 

-- temp function 
DO $$ 
DECLARE 
    db_row RECORD; 
    pk_val BIGINT; 

BEGIN 

    FOR db_row IN EXECUTE format(
     'SELECT *, 100 AS created_by_id, %L::TIMESTAMP AS creation_time FROM public.%I ORDER BY %I', 
     '2014-01-01 00:00:00', 'portfolio', 'id', 'id') 
    LOOP 
    RAISE NOTICE 'db_row.id: %', db_row.id; 
    EXECUTE 
    format(
     'SELECT $1.%I FROM audit.%I WHERE alter_type = %L AND %I = $1.%I', 
     'id', -- this will be dynamic and change when table change 
     'portfolio', -- this will be dynamic and change when table change 
     'INSERT', 
     'id', -- this will be dynamic and change when table change 
     'id' -- this will be dynamic and change when table change 
    ) 
    INTO pk_val 
    USING db_row; 
    RAISE NOTICE 'pk_val: %', pk_val; 
    END LOOP; 
END$$; 

Il semble que postgres EXECUTE ... USING db_row ne voit pas la structure complète de db_row qui est comme ligne du tableau .

Mon objectif final est de créer la fonction qui prendra un nom de table existante faire ceci:

EXECUTE 
    format(
     'SELECT $1.%I FROM audit.%I WHERE alter_type = %L AND %I = $1.%I', 
     'primary_key_col', 
     'table_name', 
     'INSERT', 
     'primary_key_col', 
     'primary_key_col' 
    ) 
    INTO pk_val 
    USING db_row 

Comment savoir postgres d'utiliser la valeur db_row.id dans cette déclaration EXECUTE?

+0

cela peut peut-être aider. http://stackoverflow.com/questions/14065271/how-to-use-execute-format-using-in-postgres-function – McNets

+0

Dans cet exemple, je connais le nom de la table, les colonnes et le nom de la clé primaire. Mais en vrai code, je ne le ferai pas. Donc, je ne peux pas utiliser 'USING db_row.id, db_row.col2' etc. – piotrekkr

Répondre

1

Le problème est que vous passez un paramètre (db_row) de type record à une instruction SQL, mais une telle valeur n'a pas de structure connue pour le moteur SQL. Vous ne pouvez même pas le convertir en type de table.

Une solution de contournement moche Je peux penser à cela pour transformer l'enregistrement à sa représentation de texte (qui fonctionne avec un appel à la fonction de sortie de type), puis cast le test au type de table désiré.

Ceci est un exemple de code qui illustre ce que je veux dire:

DO $$ 
DECLARE 
    r record; 
    n name; 
BEGIN 
    /* find all tables with a column "oid" */ 
    FOR r IN 
     SELECT t.* 
     FROM pg_class t 
       JOIN pg_attribute a ON a.attrelid = t.oid 
     WHERE a.attname = 'oid' 
    LOOP 
     /* get the table name */ 
     EXECUTE format(
       'SELECT ($1::text::%s).relname', 
       'pg_class' 
      ) INTO n USING r; 
     RAISE NOTICE 'Table name: %', n; 
    END LOOP; 
END; 
$$;