Wednesday, July 30, 2008

[pgsql-es-ayuda] Ayuda con función "avanzada"

Qué tal estoy programando una función en PLPGSQL y ya he avanzado bastante diría yo pero ahora me he topado con un problema el cual por ningún lado he podido resolver.

La función tiene como propósito el checar una tabla para encontrar similitudes entre sus datos (duplicados), para después quitarlos, por endé se le envían las columnas a comparar y el nombre de la tabla también.

Ahora he hecho que la función pueda construir las consulta necesarias, tanto para la creación de una tabla de respaldo donde trabajara y hasta ahora la consulta que detectará de forma única la "N" cantidad de elementos repetidos a los cuales debo pasar a otra tabla, la cuál solo tenga la estructura base de unicamente las columnas que se envían a través de la función, además de una columnas extra llamada "group_duplicate" la cual solo debe marcar con un identificador único a cada elmento de grupos repetidos.

Esta última consulta ya también esta, tanto para la creación de la tabla a base de las columnas enviadas.
Por ejemplo para una llamada como:

SELECT emu_winpure('articulo, autor, clasif, u_fech_mov, fech_ped, codigo', 'productos');

Obtengo estás consultas:

NOTICE: CREATE TABLE productos_winpure AS (SELECT * FROM productos)
NOTICE: ALTER TABLE productos_winpure ADD COLUMN orden_winpure SERIAL NOT NULL
NOTICE: CREATE TABLE duplicados AS (SELECT (NULL)::integer AS group_duplicate, orden_winpure, articulo, autor, clasif, u_fech_mov, fech_ped, codigo FROM productos_winpure LIMIT 0)

NOTICE:
SELECT DISTINCT ON(a.articulo, a.autor, a.clasif, a.u_fech_mov, a.fech_ped, a.codigo)
a.articulo, a.autor, a.clasif, a.u_fech_mov, a.fech_ped, a.codigo
FROM productos_winpure a, productos_winpure b
WHERE
(CASE WHEN (quita_caracter(a.articulo, ' ') IS NULL) OR (quita_caracter(b.articulo, ' ') IS NULL) THEN (1=1)::boolean ELSE (UPPER(quita_caracter(a.articulo, ' '))=UPPER(quita_caracter(b.articulo, ' ')))::boolean END)::boolean
AND (CASE WHEN (quita_caracter(a.autor, ' ') IS NULL) OR (quita_caracter(b.autor, ' ') IS NULL) THEN (1=1)::boolean ELSE (UPPER(quita_caracter(a.autor, ' '))=UPPER(quita_caracter(b.autor, ' ')))::boolean END)::boolean
AND (CASE WHEN (quita_caracter(a.clasif, ' ') IS NULL) OR (quita_caracter(b.clasif, ' ') IS NULL) THEN (1=1)::boolean ELSE (UPPER(quita_caracter(a.clasif, ' '))=UPPER(quita_caracter(b.clasif, ' ')))::boolean END)::boolean
AND (CASE WHEN (quita_caracter(a.u_fech_mov, ' ') IS NULL) OR (quita_caracter(b.u_fech_mov, ' ') IS NULL) THEN (1=1)::boolean ELSE (UPPER(quita_caracter(a.u_fech_mov, ' '))=UPPER(quita_caracter(b.u_fech_mov, ' ')))::boolean END)::boolean
AND (CASE WHEN (quita_caracter(a.fech_ped, ' ') IS NULL) OR (quita_caracter(b.fech_ped, ' ') IS NULL) THEN (1=1)::boolean ELSE (UPPER(quita_caracter(a.fech_ped, ' '))=UPPER(quita_caracter(b.fech_ped, ' ')))::boolean END)::boolean
AND (CASE WHEN (quita_caracter(a.codigo, ' ') IS NULL) OR (quita_caracter(b.codigo, ' ') IS NULL) THEN (1=1)::boolean ELSE (UPPER(quita_caracter(a.codigo, ' '))=UPPER(quita_caracter(b.codigo, ' ')))::boolean END)::boolean
ORDER BY a.articulo, a.autor, a.clasif, a.u_fech_mov, a.fech_ped, a.codigo


Las cuales se ejecutan de forma correcta pero esta consulta:

NOTICE:
SELECT DISTINCT ON(a.orden_winpure, a.articulo, a.autor, a.clasif, a.u_fech_mov, a.fech_ped, a.codigo)
a.orden_winpure, a.articulo, a.autor, a.clasif, a.u_fech_mov, a.fech_ped, a.codigo
FROM productos_winpure a
WHERE
a.articulo::varchar=$$lista.articulo$$::varchar
AND a.autor::varchar=$$lista.autor$$::varchar
AND a.clasif::varchar=$$lista.clasif$$::varchar
AND a.u_fech_mov::varchar=$$lista.u_fech_mov$$::varchar
AND a.fech_ped::varchar=$$lista.fech_ped$$::varchar
AND a.codigo::varchar=$$lista.codigo$$::varchar
ORDER BY a.orden_winpure, a.articulo, a.autor, a.clasif, a.u_fech_mov, a.fech_ped, a.codigo

Cómo verán depende de un elemento "lista" obtenido de este "for":


FOR lista IN EXECUTE consulta LOOP
cont:=cont+1;
consulta_1:=('\nSELECT DISTINCT ON(a.orden_winpure, ' || columnas || ') \n a.orden_winpure, ' || columnas || '\nFROM ' || new_table || ' a\nWHERE\n' || condiciones || '\nORDER BY a.orden_winpure, ' || columnas || '\n');
RAISE NOTICE '%', consulta_1;

FOR lista_aux1 IN EXECUTE consulta_1 LOOP
RAISE NOTICE 'En segunda consulta';
-- EXECUTE 'INSERT INTO duplicados (SELECT ' || cont || ', lista_aux1.* || ' FROM ' || new_table || ')';
END LOOP;
END LOOP;


Más sin embargo al ejecutar la consulta en el segundo "for", los valores son pasados como cadena y no como una referencia en los elementos tales como "lista.articulo" que es lo que desearía.
Poniendo la consulta de forma directa como:


consulta_1:=
'
SELECT DISTINCT ON(a.orden_winpure, a.articulo, a.autor, a.clasif, a.u_fech_mov, a.fech_ped, a.codigo)
a.orden_winpure, a.articulo, a.autor, a.clasif, a.u_fech_mov, a.fech_ped, a.codigo
FROM productos_winpure a
WHERE
a.articulo::varchar=\$\$' || lista.articulo || '\$\$::varchar
AND a.autor::varchar=\'' || lista.autor || '\'::varchar
AND a.clasif::varchar=\'' || lista.clasif || '\'::varchar
AND a.u_fech_mov::varchar=\'' || lista.u_fech_mov || '\'::varchar
AND a.fech_ped::varchar=\'' || lista.fech_ped || '\'::varchar
AND a.codigo::varchar=\'' || lista.codigo || '\'::varchar
ORDER BY a.orden_winpure, a.articulo, a.autor, a.clasif, a.u_fech_mov, a.fech_ped, a.codigo
';


Funciona bien, más sin embargo aun haciendo el código necesario para que me construya esta instrucción tal cual, me arroja un error o me toma la variable "linea.xx" de forma textual y no como referencia.
Cómo podría hacer para construir una consulta dentro de un varchar que pueda ejecutar con el comando EXECUTE y la cual haga referencia a los elementos de una variable perteneciente a un "for" superior, tal cual se presenta en los "for" aninados que les muestro arriba?

Alguna sugerencia?
_________________________________________________________________
Herramientas para combatir la crisis. MSN Dinero
http://dinero.es.msn.com/--
TIP 5: ¿Has leído nuestro extenso FAQ?
http://www.postgresql.org/docs/faqs.FAQ.html

No comments: