0

I have the following PostgreSQL script:

    CREATE OR REPLACE FUNCTION merge_fields() RETURNS VOID AS $$
     DECLARE
        current_record airport%ROWTYPE;
        new_record airport%ROWTYPE;
        column_def RECORD;
        old_value TEXT;
        new_value TEXT;
        field_name TEXT;
        sql_text  TEXT;
        integer_var INT;

     BEGIN       

        FOR current_record in SELECT * FROM airport LOOP

        -- Match Record based on iko and modified time
          SELECT * INTO new_record FROM airport WHERE 
              iko = current_record.iko AND mod_time > current_record.mod_time;             
          IF FOUND THEN 
            FOR column_def IN 

                    -- Get fields for this record
                SELECT ordinal_position, column_name, data_type 
                FROM information_schema.columns  
                WHERE 
                        table_schema = 'public' 
                AND     table_name = 'airport' 
                ORDER BY ordinal_position
                LOOP                                                

                    field_name := column_def.column_name;
                    IF ((field_name = 'gid') OR (field_name = 'mod_time')) THEN                             
                    ELSE    

-- Get each field value for current and new record.  New record is matched record.                                  
                        EXECUTE 'SELECT ($1).' || field_name || '::' || column_def.data_type INTO old_value USING current_record;
                        EXECUTE 'SELECT ($1).' || field_name || '::' || column_def.data_type INTO new_value USING new_record;                                       

                        IF new_value IS NOT NULL THEN               
                            IF new_value <> old_value THEN

                            sql_text := 'UPDATE ' || 'airport' 
                                    || ' SET '
                                    || quote_ident(field_name)
                                    || ' = ' 
                                    || quote_literal(new_value) 
                                    || ' WHERE gid = '
                                    || current_record.gid;


    -- Set current record field value same as new record field value
                                      EXECUTE 'UPDATE ' || 'airport' 
                                    || ' SET '
                                    || quote_ident(field_name)
                                    || ' = ' 
                                    || quote_nullable(new_value) 
                                    || ' WHERE gid = '
                                    || current_record.gid;

                            GET DIAGNOSTICS integer_var = ROW_COUNT;                        
                            RAISE NOTICE E'Old Value\t   rows affected: %\t ',integer_var;  

                                RAISE NOTICE E'Old Value\t   name: %\t   value: %.\n',          
                                    field_name,         
                                    old_value;                                                      
                                RAISE NOTICE E'New Value\t   name: %\t   value: %.\n',          
                                    field_name,         
                                    new_value;                                                                  

                            END IF;
                        END IF;

                    END IF; 

                -- End column enumerating loop
                 END LOOP;  


          END IF;
          IF NOT FOUND THEN        
          END IF;

        END LOOP;    

        EXCEPTION
            WHEN TOO_MANY_ROWS THEN
                     RAISE NOTICE E'Too many records match search criteria.';   
            WHEN OTHERS THEN
           --     RAISE EXCEPTION 'airports % not found';              
     END;
    $$
    LANGUAGE plpgsql;

What I am trying to do is merge two records in a database table based on the modified time. What script does is as follows:

For each record in table, I find all matching records by a key field named "iko" with modified time later than the record current record.

There will one or no matches. If a match is found, I enumerate each field in the current and matching record and synchronize the fields if the latter is not null.

Script runs as expected with no errors. Also, the diagnostic result ROW_COUNT indicates 1 row is updated After the EXECUTE command in the script is called. However, when I refresh the table, I do not see the expected change.

Any ideas why?

TIA.

4

1 に答える 1

0

示されているようにテーブルに変更が正常に行われていましたが、非TEXTデータ型をTEXT変数に割り当てようとしたスクリプトのバグが原因で、例外がスローされ、トランザクションがロールバックされていました。これは、レコードフィールドの値がTEXTでない場合にスクリプトが失敗する場所です。

-- Get each field value for current and new record.  New record is matched record.                                  
                        EXECUTE 'SELECT ($1).' || field_name || '::' || column_def.data_type INTO old_value USING current_record;
                        EXECUTE 'SELECT ($1).' || field_name || '::' || column_def.data_type INTO new_value USING new_record;  

ここで、old_valueとnew_valueは、スクリプトの前半で宣言されたTEXT変数です。

列名がわかっている場合は、次のような変数を宣言できます。

 var_name table_name.column_name%TYPE; 

これは、任意のデータ型を動的に保持します。列名が動的に検出されているため、このような変数は使用できません。これを簡単に実現する方法が思いつかなかったので、まったく別の戦略を選びました。

于 2011-09-08T16:39:44.713 に答える