jueves, 20 de octubre de 2011

Postgres - expresar números en palabras


Esta función convertirá los números en palabras. Ejm 123 -> ciento veintitrés

CREATE OR REPLACE FUNCTION base.num_a_letras(numero numeric)
  RETURNS character varying AS
$BODY$
DECLARE
-- Victor E. Milla Mora, copiado del mismo foro de postgres, pero se hizo algunos ajustes.
/* Forma de llamar :
maximo numero 999999999.99
select base.num_a_letras(123.09)
select base.num_a_letras(675)

*/

     lnEntero INTEGER;
     lcRetorno TEXT;
     lnTerna INTEGER;
     lcMiles TEXT;
     lcCadena TEXT;
     lnUnidades INTEGER;
     lnDecenas INTEGER;
     lnCentenas INTEGER;
     lnFraccion INTEGER;
     lnSw INTEGER;
BEGIN
     lnEntero := FLOOR(numero)::INTEGER;--Obtenemos la parte Entera
     lnFraccion := FLOOR(((numero - lnEntero) * 100))::INTEGER;--Obtenemos la Fraccion del Monto
     lcRetorno := '';
     lnTerna := 1;
     IF lnEntero > 0 THEN
     lnSw := LENGTH(cast(lnEntero as varchar));
     WHILE lnTerna <= lnSw LOOP
        -- Recorro terna por terna
        lcCadena = '';
        lnUnidades = lnEntero % 10;
        lnEntero = CAST(lnEntero/10 AS INTEGER);
        lnDecenas = lnEntero % 10;
        lnEntero = CAST(lnEntero/10 AS INTEGER);
        lnCentenas = lnEntero % 10;
        lnEntero = CAST(lnEntero/10 AS INTEGER);
    -- Analizo las unidades
       SELECT
         CASE /* UNIDADES */
           WHEN lnUnidades = 1 AND lnTerna = 1 THEN 'UNO ' || lcCadena
           WHEN lnUnidades = 1 AND lnTerna <> 1 THEN 'UN ' || lcCadena
           WHEN lnUnidades = 2 THEN 'DOS ' || lcCadena
           WHEN lnUnidades = 3 THEN 'TRES ' || lcCadena
           WHEN lnUnidades = 4 THEN 'CUATRO ' || lcCadena
           WHEN lnUnidades = 5 THEN 'CINCO ' || lcCadena
           WHEN lnUnidades = 6 THEN 'SEIS ' || lcCadena
           WHEN lnUnidades = 7 THEN 'SIETE ' || lcCadena
           WHEN lnUnidades = 8 THEN 'OCHO ' || lcCadena
           WHEN lnUnidades = 9 THEN 'NUEVE ' || lcCadena
           ELSE lcCadena
          END INTO lcCadena;
          /* UNIDADES */
    -- Analizo las decenas
    SELECT
    CASE /* DECENAS */
      WHEN lnDecenas = 1 THEN
        CASE lnUnidades
          WHEN 0 THEN 'DIEZ '
          WHEN 1 THEN 'ONCE '
          WHEN 2 THEN 'DOCE '
          WHEN 3 THEN 'TRECE '
          WHEN 4 THEN 'CATORCE '
          WHEN 5 THEN 'QUINCE '
          ELSE 'DIECI' || lcCadena
        END
      WHEN lnDecenas = 2 AND lnUnidades = 0 THEN 'VEINTE ' || lcCadena
      WHEN lnDecenas = 2 AND lnUnidades <> 0 THEN 'VEINTI' || lcCadena
      WHEN lnDecenas = 3 AND lnUnidades = 0 THEN 'TREINTA ' || lcCadena
      WHEN lnDecenas = 3 AND lnUnidades <> 0 THEN 'TREINTA Y ' || lcCadena
      WHEN lnDecenas = 4 AND lnUnidades = 0 THEN 'CUARENTA ' || lcCadena
      WHEN lnDecenas = 4 AND lnUnidades <> 0 THEN 'CUARENTA Y ' || lcCadena
      WHEN lnDecenas = 5 AND lnUnidades = 0 THEN 'CINCUENTA ' || lcCadena
      WHEN lnDecenas = 5 AND lnUnidades <> 0 THEN 'CINCUENTA Y ' || lcCadena
      WHEN lnDecenas = 6 AND lnUnidades = 0 THEN 'SESENTA ' || lcCadena
      WHEN lnDecenas = 6 AND lnUnidades <> 0 THEN 'SESENTA Y ' || lcCadena
      WHEN lnDecenas = 7 AND lnUnidades = 0 THEN 'SETENTA ' || lcCadena
      WHEN lnDecenas = 7 AND lnUnidades <> 0 THEN 'SETENTA Y ' || lcCadena
      WHEN lnDecenas = 8 AND lnUnidades = 0 THEN 'OCHENTA ' || lcCadena
      WHEN lnDecenas = 8 AND lnUnidades <> 0 THEN 'OCHENTA Y ' || lcCadena
      WHEN lnDecenas = 9 AND lnUnidades = 0 THEN 'NOVENTA ' || lcCadena
      WHEN lnDecenas = 9 AND lnUnidades <> 0 THEN 'NOVENTA Y ' || lcCadena
      ELSE lcCadena
    END INTO lcCadena; /* DECENAS */
    -- Analizo las centenas
    SELECT
    CASE /* CENTENAS */
      WHEN lnCentenas = 1 AND lnUnidades = 0 AND lnDecenas = 0 THEN 'CIEN ' || lcCadena
      WHEN lnCentenas = 1 AND NOT(lnUnidades = 0 AND lnDecenas = 0) THEN 'CIENTO ' || lcCadena
      WHEN lnCentenas = 2 THEN 'DOSCIENTOS ' || lcCadena
      WHEN lnCentenas = 3 THEN 'TRESCIENTOS ' || lcCadena
      WHEN lnCentenas = 4 THEN 'CUATROCIENTOS ' || lcCadena
      WHEN lnCentenas = 5 THEN 'QUINIENTOS ' || lcCadena
      WHEN lnCentenas = 6 THEN 'SEISCIENTOS ' || lcCadena
      WHEN lnCentenas = 7 THEN 'SETECIENTOS ' || lcCadena
      WHEN lnCentenas = 8 THEN 'OCHOCIENTOS ' || lcCadena
      WHEN lnCentenas = 9 THEN 'NOVECIENTOS ' || lcCadena
      ELSE lcCadena
    END INTO lcCadena;/* CENTENAS */
    -- Analizo la terna
    SELECT
    CASE /* TERNA */
      WHEN lnTerna = 1 THEN lcCadena
      WHEN lnTerna = 2 AND (lnUnidades + lnDecenas + lnCentenas <> 0) THEN lcCadena || ' MIL '
      WHEN lnTerna = 3 AND (lnUnidades + lnDecenas + lnCentenas <> 0) AND
        lnUnidades = 1 AND lnDecenas = 0 AND lnCentenas = 0 THEN lcCadena || ' MILLON '
      WHEN lnTerna = 3 AND (lnUnidades + lnDecenas + lnCentenas <> 0) AND
        NOT (lnUnidades = 1 AND lnDecenas = 0 AND lnCentenas = 0) THEN lcCadena || ' MILLONES '
      WHEN lnTerna = 4 AND (lnUnidades + lnDecenas + lnCentenas <> 0) THEN lcCadena || ' MIL MILLONES '
      ELSE ''
    END INTO lcCadena;/* TERNA */

    --Retornamos los Valores Obtenidos
    lcRetorno = lcCadena  || lcRetorno;
    lnTerna = lnTerna + 1;
    END LOOP;
  END IF;
  IF lnTerna = 1 THEN
    lcRetorno := 'CERO';
  END IF;
  lcRetorno := lcRetorno || ' CON ' || lpad(trim(both ' ' from cast(lnFraccion as varchar)) ,2,'0') || '/100 NUEVOS SOLES';
RETURN lcRetorno;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION base.num_a_letras(numeric) OWNER TO postgres;

Postgres - Hallar edad de una persona


Esta función te dará la edad de una persona entregándolo como parámetros dos fechas


CREATE OR REPLACE FUNCTION base.edad(dfecha_ini date, dfecha_fin date)
  RETURNS character varying AS
$BODY$

declare
cinterv varchar(50);
BEGIN
/* select base.edad(cast('1974-11-06'as date), cast('2009-02-11'as date)) */
cinterv:= (select age(dfecha_fin +1,dfecha_ini));
cinterv:= replace(cinterv, 'years','años');
cinterv:= replace(cinterv, 'year','año');

cinterv:= replace(cinterv, 'mons','meses');
cinterv:= replace(cinterv, 'mon','mes');

cinterv:= replace(cinterv, 'days','días');
cinterv:= replace(cinterv, 'day','día');

return cinterv;
   
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION base.edad(date, date) OWNER TO postgres;

Postgres - función para hallar duplicados de personal en una tabla


La tabla se llama PERSONAL y tiene los campos de tipo varchar:
pers_id -> identificación
pers_pat -> apellido paterno
pers_mat -> apellido materno
pers_nom -> nombres

La idea es saber qué personas tienen registros duplicados


CREATE OR REPLACE FUNCTION base.duplicado_personal_hallar(cschema character varying)
  RETURNS SETOF record AS
$BODY$

declare
r record; cpat varchar := '';  cmat varchar := '';  cnom varchar := '';
BEGIN
execute 'set search_path to ' || cschema || ', base, public' ;

create temp table tmp_persdup (pers_id character varying(20) ,  pers_pat character varying(25) DEFAULT '',
pers_mat character varying(25) DEFAULT '',  pers_nom character varying(30) DEFAULT '' ) on commit drop  ;

for r in select pers_id, pers_pat, pers_mat, pers_nom from personal
order by pers_pat, pers_mat, pers_nom
loop
if r.pers_pat = cpat and r.pers_mat= cmat and r.pers_nom= cnom then
insert into tmp_pers_dup (pers_id, pers_pat,pers_mat, pers_nom) values
(r.pers_id, r.pers_pat ,r.pers_mat, r.pers_nom);
end if;
cpat := r.pers_pat; cmat := r.pers_mat; cnom:= r.pers_nom;
end loop;

return query select pers_id, pers_pat ,pers_mat, pers_nom from tmp_persdup;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100
  ROWS 1000;
ALTER FUNCTION base.duplicado_personal_hallar(character varying) OWNER TO postgres;

VFP - Funciones para manejar nombres y números de columnas Excel

* Esta función es para Visual Fox y te permite saber el nombre de la columna en letras a partir de un número entero.
ejemplo: 2 = columna B, 27 = columna AA

function xls_ncol_let
LPARAMETERS nNumero
name=''
d= nNumero
DO WHILE d>0
m = MOD((d - 1),26)
                name = Chr(65 + m) + name
               d = Int((d - m) / 26)
    ENDDO
RETURN name
ENDFUNC


**************************************************************

* Esta función retorna el número de columna de excel a partir de una cadena de letras
ejemplo: B= 2, AA= 27

FUNCTION xls_let_ncol
LPARAMETERS cLetras

nAcum = 0
nPot = -1
FOR j= LEN(cLetras) TO 1 STEP -1
nPot = nPot +1
cChar = SUBSTR(cLetras,j,1)
nAcum = nAcum + ( (ASC(cChar)-64) * 26 ^nPot)
ENDFOR

RETURN nAcum
ENDFUNC