Esta respuesta es similar a otra que hicieron una vez y yo la respondi: 1) Puedes usar un trigger before insert or update que le cree el proximo usando usa secuencia (no hay necesidad de usar esa tabla TGeneradorCodigoVentas)
2) Si puede ser autoincremental el cod_venta usa un tipo serial o bigserial a la hora de declarar la tabla. * En ambos casos, seria buena idea declarar una unique constraint ________________________________ De: cesar salcedo <[email protected]> Para: [email protected] Enviado: lunes 24 de octubre de 2011 19:07 Asunto: [pgsql-es-ayuda] GENERAR CODIGOS DE VENTA SIN DUPLICADOS EN POSTGRESQL ( ESTARA BIEN ? ) Hola como están espero que me puedan ayudar con una duda que me está rondando la cabeza desde hace ya varios días , bueno vamos al asunto ,tengo estas tablas : CREATE TABLE "TGeneradorCodigoVentas" ( Ultimo_CodVenta CHAR(14) NOT NULL , -- 'DVEN-000000001' PRIMARY KEY (Ultimo_CodVenta) ); CREATE TABLE "TDoc_Venta" -- representa los datos de cabecera del documento de venta ( Cod_Venta CHAR(14) NOT NULL, -- 'DVEN-000000001' TipoDocumento CHAR(4) NOT NULL CHECK(TipoDocumento IN ('PROF','BOLE','FACT')), Serie_Documento CHAR(3) NOT NULL,--002 Cod_Documento VARCHAR(7) NOT NULL,-- 0000265 Id_Tienda CHAR(8) NOT NULL Id_Cliente CHAR(13) NOT NULL, Id_Usuario CHAR(8) NOT NULL, Fecha_Venta TIMESTAMP NOT NULL, .....etc PRIMARY KEY (Cod_Venta,TipoDocumento,Serie_Documento,Cod_Documento,Id_Tienda), FOREIGN KEY (Id_Tienda) REFERENCES "TTienda", ..... ); el asunto es que deseo generar los códigos de venta y que no se me dupliquen para otros usuarios ya que en cada tienda existen 8 ventanillas de cobro o cajeros , sin nombrar que la empresa posee varias sucursales con las mismas características(varios cajeros) mi código es : CREATE OR REPLACE FUNCTION Sfu_GenerarNuevoCodigoDctoVenta() RETURNS TEXT AS $$ DECLARE NuevoCodVenta CHAR(14); ParteNumCodActual INT; BEGIN SELECT (SubString(Ultimo_CodVenta FROM 6 FOR 14) :: INT) INTO ParteNumCodActual FROM "TGeneradorCodigoVentas"; --Luego generamos el nuevo código de venta IF ParteNumCodActual IS NULL THEN -- Quiere decir que la tabla esta vacía NuevoCodVenta := 'DVEN-' || LPAD(1::TEXT,9,'0'); ELSE -- La tabla ya contiene datos NuevoCodVenta := 'DVEN-' || LPAD((ParteNumCodActual +1)::TEXT,9,'0'); END IF; RETURN NuevoCodVenta; END $$ LANGUAGE 'plpgsql'; CREATE OR REPLACE FUNCTION Sfu_InsertNuevaVenta ( ....) RETURNS TEXT AS $$ DECLARE Var_Mensaje TEXT; IN_CodVenta CHAR(14); ..... BEGIN --Obtenemos el siguiente código para el documento de venta IN_CodVenta := Sfu_GenerarNuevoCodigoDctoVenta(); UPDATE "TGeneradorCodigoVentas" SET Ultimo_CodVenta = IN_CodVenta ; .... --Finalmente Insertamos los Datos de la Venta INSERT INTO "TDoc_Venta" (Cod_Venta, , ,.....) VALUES (IN_CodVenta, ,....) ..... Var_Mensaje:='LOS DATOS DE LA VENTA SE GRABARON CORRECTAMENTE' ; RETURN Var_Mensaje; END $$ LANGUAGE 'plpgsql'; LA DUDA está en que en el modulo de ventas como puedo garantizar que este código que estoy generando ('DVEN-00000000N') con la función anterior no se repita para otras ventanillas de cobro ,ósea si el cajero 1 está realizando una venta y al MISMO TIEMPO otros cajeros de la misma tienda están registrando otras ventas ,que debería hacer para garantizar que el código sea diferente para todos ellos ósea ('DVEN-00000000N' , 'DVEN-00000000(N+1)', para el otro cajero ,'DVEN-000000009(N+2)' para el sigte y así ) Tendría que usar LOCK TABLE en algún lugar , tendría que usar TRANSACCIONES SERIALIZABLES (esperar a que un cajero termine de realizar una venta para recién generar otro código ),o la misma función (Sfu_InsertNuevaVenta) por tener una transacción implícita ya es suficiente , o que tipo de bloqueos usa postgresl 9.0 será READ COMMITTED , o SERIALIZABLE vamos muchachos por favor seria chévere que opinen o si desean ayudarme en privado : [email protected] gracias de antemano he , un saludo desde Perú . Ha y porque cojo los códigos de otra tabla y no hago algo así como : SELECT MAX (SubString(Ultimo_CodVenta FROM 6 FOR 14) :: INT) INTO ParteNumCodActual FROM "TGeneradorCodigoVentas" NuevoCodVenta := 'DVEN-' || LPAD((ParteNumCodActual +1)::TEXT,9,'0'); Pues porque la tabla de Ventas crece demasiado rápido con tantas ventas que se hacen por día y hacer un MAX es muy costoso
