Re: longitud tipo dato serial

From: Gunnar Wolf <gwolf(at)gwolf(dot)org>
To: Gustavo Rosso <grosso(at)sadaic(dot)org(dot)ar>
Cc: Victor Avendaño <avenda(at)gmail(dot)com>, pgsql-es-ayuda(at)postgresql(dot)org
Subject: Re: longitud tipo dato serial
Date: 2010-04-13 18:12:29
Message-ID: 20100413181229.GF10143@gwolf.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-es-ayuda

Gustavo Rosso dijo [Mon, Mar 22, 2010 at 10:53:18AM -0300]:
>> Parece que me expresé mal, no necesariamente necesito un tipo de
>> datos, pero sería genial que así se pudiera generar, lo que deseo es
>> poder tener algo como un character varing de longitud 3 que sea
>> autoincrementable, osea que se baya generando de la siguiente manera
>> 001, 002, 003..... 012,013,014, ... etc debido a que necesito grabar
>> esos 3 caracteres y como serial no me conserva los ceros, quizas otra
>> solucion seria poder guardar el serial pero con los ceros delante cosa
>> que yo al traerlos o exportarlos siempre pueda manipular esos 3
>> caracteres... me explico???
>
> Un trigger que llame a una funcion antes del insert?

(Sí, esta es una consulta más bien vieja, pero bueno... Me sorprende
que nadie haya dicho esto hasta ahora ;-) )

Gustavo, el meollo de esto es para qué quieres _guardarlo_ en ese
formato. Un campo serial es por naturaleza entero, esto agiliza su
manejo interno (ordenamiento, búsqueda, comparación).

Un campo de tipo entero _no tiene_ representación directa. Esto es, en
la representación física de los datos (en el disco) no aparece el
valor '1', '2', '3', etcétera — Aparece un campo de 32 bits que tiene
el valor numérico en cuestión, pero no de una manera que tú lo puedas
leer. Ilustro, con una conversión bastante simplista. En Ruby:

def disgrega(palabra)
(0..palabra.size-1).map{|i| palabra[i]}
end

def suma(arreglo=[])
return 0 if arreglo.empty?
return arreglo[-1].to_i + 256*suma(arreglo[0..-2])
end

La primer función separa una cadena en sus bytes constitutivos:

>> disgrega('hola')
=> [104, 111, 108, 97]

La segunda función los suma, multiplicando cada posición por 256, para
formar un entero. Esto es,

>> suma(disgrega('hola'))
=> 1752132705

Ahora, ¿qué pasa con la representación que buscas guardar? Veamos:

>> suma(disgrega('001'))
=> 3158065
>> suma(disgrega('002'))
=> 3158066
>> suma(disgrega('003'))
=> 3158067

Esto porque, claro está, cada '0' vale 48. Entonces, si bien en la
práctica podrías lograr tu propósito representando enteros como
cadenas, sería altamente ineficiente. Las comparaciones funcionarían,
aunque dejarían huecos – Por ejemplo:

>> suma(disgrega('009'))
=> 3158073
>> suma(disgrega('010'))
=> 3158320

Acá tienes un brinco de 247 (esto es, 256-9, ¿te queda claro por qué?
:-) )

Bueno, a lo que iba con todo esto: Te conviene guardar los datos en un
campo entero. A PostgreSQL le es mucho más agradable trabajar con este
tipo de datos, y lo hace rápido y de buena gana. Las cadenas siempre
duelen y lo ponen de mal humor. Y tú no quieres eso.

Obviamente, quieres manejar el consecutivo formateado en tu
aplicación. Acá, una de dos: O formateas desde Postgres _después_ de
obtener el valor (SELECT lpad(id::text, 3, '0') FROM tabla WHERE ...),
o manejas el valor íntegramente como numérico dentro de Postgres y le
das formato en tu aplicación, al momento de presentarla al usuario
(p.ej. con un sprintf('%03d', id) o su equivalente en tu lenguaje
favorito).

Pero bueno, en resumen: Te conviene separar el dato de su
presentación. No creo que haya ninguna razón _real_ para que busques
almacenarlo con los ceros precedentes. Sólo al presentarlo al
usuario.

Saludos,

--
Gunnar Wolf • gwolf(at)gwolf(dot)org • (+52-55)5623-0154 / 1451-2244

In response to

Responses

Browse pgsql-es-ayuda by date

  From Date Subject
Next Message Hector R. De los Santos 2010-04-13 18:28:45 Re: longitud tipo dato serial
Previous Message Mariano Reingart 2010-04-13 02:34:39 == PostgreSQL: Noticias semanales - 11 de Abril de 2010 ==