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