Pregunta

Tengo el siguiente script PostgreSQL:

    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;

Lo que estoy tratando de hacer es fusionar dos registros en una tabla de base de datos basada en el tiempo modificado. Lo que hace el script es el siguiente:

Para cada registro en la tabla, encuentro todos los registros coincidentes mediante un campo clave llamado "IKO" con tiempo modificado más tarde que el registro de registro de registro.

Habrá uno o ningún partido. Si se encuentra una coincidencia, enumero cada campo en el registro actual y coincidente y sincronizo los campos si este último no es nulo.

El script se ejecuta como se esperaba sin errores. Además, el resultado de diagnóstico ROW_COUNT indica que 1 fila se actualiza después de que se llama al comando Ejecutar en el script. Sin embargo, cuando actualizo la mesa, no veo el cambio esperado.

¿Alguna idea por qué?

Tia.

¿Fue útil?

Solución

Se hicieron cambios en la tabla con éxito como se indicó, pero debido a un error en el script, donde estaba tratando de asignar tipos de datos de texto a una variable de texto, se estaba lanzando una excepción, lo que provocó que la transacción se reduzca hacia atrás. Aquí es donde el script está fallando si el valor del campo de registro no es texto.:

-- 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;  

donde Old_Value y New_Value son variables de texto declaradas anteriormente en el script.

Si se conoce el nombre de la columna, se puede declarar una variable como

 var_name table_name.column_name%TYPE; 

que contendría dinámicamente cualquier tipo de datos. Porque, el nombre de la columna se descubre dinámicamente, tal variable no se puede usar. No podía pensar en una forma de lograr esto fácilmente, así que elegí una estrategia completamente diferente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top