Jump to content


Photo

Pasar variable entera vacia al server


  • Please log in to reply
15 replies to this topic

#1 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 posts

Posted 07 May 2015 - 08:09 AM

Tengo el metodo de facturacion donde si es un ticket comun no se registra el cliente y si es cuenta corriente si. Para el primer caso el idcliente que paso al metodo desl server debe ser nulo.

 

De lo contrario se podria reservar en la base de datos un registro para el cliente comun por asi decirlo.. y asignar estaticamente este valor.

 

Pero queria consultar tengo la variable idcliente en la aplicacion cliente. Intente con:


delphi
  1. idcliente=null;
  2. idcliente=nil;

pero no funciona. como asigna un nulo?


  • 0

#2 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 posts
  • LocationArgentina

Posted 07 May 2015 - 04:34 PM

Yo defino costantes de lo que "para mi" es un nulo

 

Ejemplo:

 

EMPTY_INTEGER = -1;

 

o bien

 

NULL_INTEGER = -1;


  • 0

#3 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2137 posts

Posted 08 May 2015 - 07:09 AM

La idea que te da OrtuAgustin es buena, luego si por causa de la integridad referencial en la DB no puedes almacenar el -1 entonces basta un trigger en la DB, en  BEFORE INSERT donde comparas si el nuevo valor es -1 entonces le asignas NULL.

 

Saludos.


  • 0

#4 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 posts

Posted 08 May 2015 - 11:43 PM

La idea que te da OrtuAgustin es buena, luego si por causa de la integridad referencial en la DB no puedes almacenar el -1 entonces basta un trigger en la DB, en  BEFORE INSERT donde comparas si el nuevo valor es -1 entonces le asignas NULL.

 

Saludos.

 

hice lo siguiente, pero no inserta, entonces hice un debug del server utilizando el cliente, y definitivamente me da error por la referencia a cliente:


sql
  1. delimiter $$
  2. CREATE TRIGGER idc BEFORE INSERT ON ferreteracentral.ticket FOR each ROW
  3. BEGIN
  4. IF (NEW.idcliente=-1) THEN
  5. SET NEW.idcliente=NULL;
  6. END IF;
  7. END;

aqui la declaracion de tablas ticket y cliente..


sql
  1. CREATE TABLE cliente(
  2. idcliente INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  3. idpersona INT,
  4. cuit INT,
  5. cuil INT,
  6. deuda DECIMAL(10,2),
  7. cupodias INTEGER,
  8. cupopesos DECIMAL(10,2),
  9. cupocheques DECIMAL(10,2),
  10. cupochequestro DECIMAL(10,2),
  11. descuento DECIMAL(10,2),
  12. FOREIGN KEY (idpersona) REFERENCES persona(idpersona)
  13. );
  14.  
  15. CREATE TABLE ticket(
  16. idticket INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  17. idcliente INTEGER,
  18. numero INTEGER,
  19. importe DECIMAL(10,2),
  20. fechae DATE,
  21. horae TIME,
  22. idsucursal INT,
  23. tipo CHAR,
  24. efectivo DECIMAL(10,2),
  25. vuelto DECIMAL(10,2),
  26. FOREIGN KEY (idsucursal) REFERENCES sucursal(idsucursal) ON DELETE no action,
  27. FOREIGN KEY (idcliente) REFERENCES cliente(idcliente) ON DELETE no action
  28. );

me fije en alter table y el default de idcliente en ticket es null...


  • 0

#5 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2137 posts

Posted 11 May 2015 - 07:10 PM

Que base de datos estás usando?


  • 0

#6 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 posts

Posted 12 May 2015 - 10:14 AM

Que base de datos estás usando?

uso mysql.. y use show triggers y me muestra el trigger de arriba..

 

Ahora funciono, debe ser porque reinicie todo..ajaj disculpen..

El problema que daba no es ese sino con la tabla ventas que contiene el detalle del ticket:

 

VENTAS(idticket,idproducto,preciou,cantidad)

 

Exception class TDBXError with message 'Cannot add or update a child row: a foreign key constraint fails (`ferreteracentral`.`venta`, CONSTRAINT `venta_ibfk_1` FOREIGN KEY (`idticket`) REFERENCES `ticket` (`idticket`))'. Process Project1.exe (2660)

 

Para insertar el detalle uso el siguiente query:


sql
  1. SELECT MAX(idticket)FROM ticket;


  • 0

#7 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2137 posts

Posted 12 May 2015 - 12:20 PM

Haber si logro entender, tienes otra tabla de nombre VENTAS? Que a su vez es una tabla de detalles de la la tabla ticket? Realmente creo que deberías considerar dar nombres más acordes a  las tablas, la entidad Ticked y la entidad Ventas en realidad son la misma cosa (idVenta, IdCliente, fecha, numero, idSucursal, tipo, importe, etc); y la tabla para llevar los detalles de las ventas debería llamarse algo así Detalles_Ventas : (idDetalle, IdVenta, IdProducto,Cantidad, PrecioUnitario, etc), para más claridad.

 

 

 

 

Para insertar el detalle uso el siguiente query:


sql
  1. SELECT MAX(idticket)FROM ticket;

 

En una aplicación multi-usuario esta manera de obtener el valor para una clave primaria o foránea es muy mala idea.

 

 

 

 

VENTAS(idticket,idproducto,preciou,cantidad)

 

Exception class TDBXError with message 'Cannot add or update a child row: a foreign key constraint fails (`ferreteracentral`.`venta`, CONSTRAINT `venta_ibfk_1` FOREIGN KEY (`idticket`) REFERENCES `ticket` (`idticket`))'. Process Project1.exe (2660)

 

 

El error es típico cuando se está tratando de referenciar una clave foránea con un valor que aún no existe en la DB, cuando se trata de una inserción de una venta nueva lo que yo hago es: mediante una función obtengo el valor para el identificador de la nueva venta bien sea mediante un generador, obteniendo el valor de la última venta e incrementarlo en uno, o las opciones que el motor de la db ofrezca, luego con ese valor inicializo la venta y los de talles de la venta, luego ya es mirar el procedimiento para grabar primero en la tabla maestra y luego en la de detalles, para la que existen muchas formas de hacerlo según los componentes de conexión.

 

Muéstranos el procedimiento con el cual grabas una venta nueva para poder ayudarte.

 

Saludos.


  • 0

#8 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 posts

Posted 12 May 2015 - 03:47 PM

Haber si logro entender, tienes otra tabla de nombre VENTAS? Que a su vez es una tabla de detalles de la la tabla ticket? Realmente creo que deberías considerar dar nombres más acordes a  las tablas, la entidad Ticked y la entidad Ventas en realidad son la misma cosa (idVenta, IdCliente, fecha, numero, idSucursal, tipo, importe, etc); y la tabla para llevar los detalles de las ventas debería llamarse algo así Detalles_Ventas : (idDetalle, IdVenta, IdProducto,Cantidad, PrecioUnitario, etc), para más claridad.

 

 

 

En una aplicación multi-usuario esta manera de obtener el valor para una clave primaria o foránea es muy mala idea.

 

 

 

El error es típico cuando se está tratando de referenciar una clave foránea con un valor que aún no existe en la DB, cuando se trata de una inserción de una venta nueva lo que yo hago es: mediante una función obtengo el valor para el identificador de la nueva venta bien sea mediante un generador, obteniendo el valor de la última venta e incrementarlo en uno, o las opciones que el motor de la db ofrezca, luego con ese valor inicializo la venta y los de talles de la venta, luego ya es mirar el procedimiento para grabar primero en la tabla maestra y luego en la de detalles, para la que existen muchas formas de hacerlo según los componentes de conexión.

 

Muéstranos el procedimiento con el cual grabas una venta nueva para poder ayudarte.

 

Saludos.

Claro como no..

para mi es la transaccion que no deja ver el ultimo registro... es mas hice un:


delphi
  1. ShowMessage(IntoToStr(quticket.ExecSQL()));

donde quticket contiene max(idticket). Y el server me muestra el valor 1.

Antes habia utilizado last_insert_id, pero si falla la transaccion el valor no se restaura, es decir tenemos el ticket 17 falla la insercion del 18 y en la siguiente insercion se va a insertar el 19, pero en la tabla ventas o detalle de la factura se inserta referenciando al ticket 17.

 

Aqui el metodo de cabecera del ticke t ysu detalle:


delphi
  1. procedure TServerMethods1.nuevoticket(numero,ids,idcliente:integer;importe,efectivo,vuelto:Double;fechae,horae,tipo:string);
  2. var
  3. tr:TDBXTransaction;
  4. begin
  5. if (SUCURSAL.InTransaction) then
  6. raise Exception.Create('Hay una transacción pendiente');
  7. SUCURSAL.Open;
  8. try
  9. try
  10. tr:=SUCURSAL.BeginTransaction();
  11.  
  12. begin
  13. with qticket do
  14. begin
  15. Close;
  16. ParamByName('numero').AsInteger:=numero;
  17. ParamByName('importe').AsFloat:=importe;
  18. ParamByName('fechae').AsString:=fechae;
  19. ParamByName('horae').AsString:=horae;
  20. ParamByName('idsucursal').AsInteger:=ids;
  21.  
  22. ParamByName('idcliente').AsInteger:=idcliente;
  23. ParamByName('tipo').AsString:=tipo;
  24. ParamByName('efectivo').AsFloat:=efectivo;
  25. ParamByName('vuelto').AsFloat:=vuelto;
  26. ExecSQL();
  27. end;
  28.  
  29. SUCURSAL.CommitFreeAndNil(tr);
  30. end;
  31.  
  32. except
  33. SUCURSAL.RollbackFreeAndNil(tr);
  34. end;
  35. finally
  36. SUCURSAL.Close;
  37. end;
  38. end;
  39. procedure TServerMethods1.nuevodetalleticket(idp:integer;cantidad,preciou:Double);
  40. var
  41. tr:TDBXTransaction;
  42. begin
  43. if (SUCURSAL.InTransaction) then
  44. raise Exception.Create('Hay una transacción pendiente');
  45. SUCURSAL.Open;
  46. try
  47. try
  48. tr:=SUCURSAL.BeginTransaction();
  49.  
  50. begin
  51. with qventa do
  52. begin
  53. Close;
  54. // ShowMessage(IntToStr(quticket.ExecSQL()));
  55. ParamByName('idt').AsInteger:=quticket.ExecSQL();
  56. ParamByName('idp').AsInteger:=idp;
  57. ParamByName('cantidad').AsFloat:=cantidad;
  58. ParamByName('preciou').AsFloat:=preciou;
  59. ExecSQL();
  60. end;
  61.  
  62. SUCURSAL.CommitFreeAndNil(tr);
  63. end;
  64.  
  65. except
  66. SUCURSAL.RollbackFreeAndNil(tr);
  67. end;
  68. finally
  69. SUCURSAL.Close;
  70. end;
  71. end;

Saludos


  • 0

#9 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2137 posts

Posted 12 May 2015 - 05:48 PM

Tienes un problema conceptual, tienes dos transacciones diferentes para el encabezado y para los detalles, en realidad el proceso de grabación de una nueva venta debería estar dentro de una sola transacción, en tu modelo bien podrían grabarse encabezados y si falla la inserción de un detalle, podrían quedar encabezados sin detalles, sin Delphi a mano te he escrito algo de código (con base en el tuyo) de como podría ser el proceso, asumiendo que en la aplicación cliente vas llenando los detalles de la venta en un dataset. 


delphi
  1. function NuevoIDVenta: integer;
  2. begin
  3. // result
  4. end;
  5.  
  6. procedure TServerMethods1.nuevoticket(idTicket, numero, ids, idcliente: integer;
  7. importe, efectivo, vuelto: Double; fechae, horae, tipo: string;
  8. detalles: TDataset);
  9. var
  10. tr: TDBXTransaction;
  11. id: integer;
  12. begin
  13. if (SUCURSAL.InTransaction) then
  14. raise Exception.Create('Hay una transacción pendiente');
  15. SUCURSAL.Open;
  16. try
  17. try
  18. tr := SUCURSAL.BeginTransaction();
  19. id := NuevoIDVenta;
  20. begin
  21. with qticket do
  22. begin
  23. Close;
  24. ParamByName('idTicket').AsInteger := id;
  25. ParamByName('numero').AsInteger := numero;
  26. ParamByName('importe').AsFloat := importe;
  27. ParamByName('fechae').AsString := fechae;
  28. ParamByName('horae').AsString := horae;
  29. ParamByName('idsucursal').AsInteger := ids;
  30.  
  31. ParamByName('idcliente').AsInteger := idcliente;
  32. ParamByName('tipo').AsString := tipo;
  33. ParamByName('efectivo').AsFloat := efectivo;
  34. ParamByName('vuelto').AsFloat := vuelto;
  35. ExecSQL();
  36. end;
  37.  
  38. // Tratamiento de detalles
  39.  
  40. detalles.Open;
  41. detalles.first;
  42.  
  43. while not detalles.eof do //recorre el dataset
  44. begin
  45. qVenta.Close;
  46.  
  47. qVenta.ParamByName('idt').AsInteger := id;
  48.  
  49. qVenta.ParamByName('idp').AsInteger := detalles.FieldByName('idp')
  50. .AsInteger;
  51.  
  52. qVenta.ParamByName('cantidad').AsFloat :=
  53. detalles.FieldByName('cantidad').AsFloat;
  54.  
  55. qVenta.ParamByName('preciou').AsFloat :=
  56. detalles.FieldByName('precio').AsFloat;
  57.  
  58. qVenta.ExecSQL();
  59.  
  60. detalles.Next;
  61. end;
  62. // fin tratamiento detalles
  63.  
  64. SUCURSAL.CommitFreeAndNil(tr);
  65. end;
  66.  
  67. except
  68. SUCURSAL.RollbackFreeAndNil(tr);
  69. end;
  70. finally
  71. SUCURSAL.Close;
  72. end;
  73. end;

He colocado una función para obtener un identificador único para la clave principal de tickects, no soy experto en MySql por lo tanto no se como maneja los campos autoincrementales, pero debería haber alguna forma de obtener el valor siguiente para un campo autoincremental (busca en google), de lo contrario es fácil implementarlo creando una tabla con un solo campo de tipo entero que se podría manejar e incrementar dentro de la transacción para obtener un identificador único por venta (obviamente habría que cambiar la declaración del campo en la tabla de tickets). 

 

También he agregado dos nuevos parámetros al procedimiento (idTicket de tipo entero para pasar la clave primaria a la tabla maestra y Detalles de tipo TDataset para manejar los detalles de la venta).

 

 

Saludos.

 

PD: En Datasnap hay una técnica muy efectiva para manejar las relaciones Maestro-Detalles que son los Dataset anidados, si quieres considerar esta opción en este mismo foro de Datasnap hay varios hilos al respecto.


  • 0

#10 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 posts

Posted 12 May 2015 - 06:25 PM

Te explico mi concepto: la tabla venta no lleva id porque es una tabla de relacion varios a varios entre un ticket y todos sus productos, en ella esta el idticket y el idproducto, junto a precio y cantidad. Si esa tabla tendria un clave primaria como dice no seria tanto problema, pero no es tabla maestra es varios a varios.. Un producto aparece en varios tickets y un ticket puede tener varios productos.. 

Por otro lado el idticket que tu envias como parametro es autogenerado en mysql. ni siquiera en el server lo indico..

 

Si es correcto lo que explicas de tener un procedimiento almacenado que genere los ids pero eso estaria en el motor de la base de datos.. La funcion que me recomiendas es hacer un select del ultimo registro, para reservarlo(sumandole 1).. ya que si hay varias sucursales haciendo tickets se generara un conflicto..

 

Y la funcion last_insert_id() tampoco es la solucion... porque estuve leyendo que funciona sobre cada cliente, y no sobre toda la tabla..


  • 0

#11 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2137 posts

Posted 12 May 2015 - 07:58 PM

Te explico mi concepto: la tabla venta no lleva id porque es una tabla de relacion varios a varios entre un ticket y todos sus productos.

 

Eso está claro desde siempre y no cambia para nada lo que te he dicho.

 

 

 

Por otro lado el idticket que tu envias como parametro es autogenerado en mysql. ni siquiera en el server lo indico..

 

 

Por eso te decía que debería haber la forma en MySql de averiguar (y actualizar) el nuevo valor de un campo autoincremental (en Firebrird es muy fácil con los generadores).

 

 

 

Si es correcto lo que explicas de tener un procedimiento almacenado que genere los ids pero eso estaria en el motor de la base de datos.. La funcion que me recomiendas es hacer un select del ultimo registro, para reservarlo(sumandole 1).. ya que si hay varias sucursales haciendo tickets se generara un conflicto..

 

 

Por supuesto que no es viable el (select max), por eso te decía que de no haber forma de obtener el dato del campo autoincremental directamente desde el motor de la BD, entonces es posible solventarlo creando una tabla, por ejemplo TABLA_GEN_ID_VENTAS con un solo campo ULTIMO_ID de tipo entero,e insertas un registro con valor 1 (uno). Para que esto funcione solo debes cambiar el tipo de campo idTicket en la tabla tikects para que sea solo entero y no autoincremental. 

 

Luego la función de la que te hablo sería mas o menos así:


delphi
  1. function NuevoIDVenta: integer;
  2. var
  3. qry: TSQLQuery;
  4. begin
  5. qry := TSQLQuery.Create(nil);
  6. try
  7. qry.SQLConnection := TuConexion;
  8. qry.SQL.Add('UPDATE TABLA_GEN_ID_VENTAS SET ULTIMO_ID = ULTIMO_ID +1');
  9. qry.ExecSQL();
  10. qry.SQL.Clear;
  11. qry.SQL.Add('SELECT ULTIMO_ID FROM TABLA_GEN_ID_VENTAS');
  12. qry.Open;
  13. result := qry.FieldByName('ULTIMO_ID').AsInteger - 1;
  14. finally
  15. qry.Free;
  16. end;
  17. end;
  18.  
  19. procedure TServerMethods1.nuevoticket(idTicket, numero, ids, idcliente: integer;
  20. importe, efectivo, vuelto: Double; fechae, horae, tipo: string;
  21. detalles: TDataset);
  22. var
  23. tr: TDBXTransaction;
  24. id: integer;
  25. begin
  26. if (SUCURSAL.InTransaction) then
  27. raise Exception.Create('Hay una transacción pendiente');
  28. SUCURSAL.Open;
  29.  
  30. id := NuevoIDVenta; //Llamamos la función por fuera de la transacción.
  31. try
  32. try
  33. tr := SUCURSAL.BeginTransaction();
  34.  
  35. begin
  36. with qticket do
  37. begin
  38. Close;
  39. ParamByName('idTicket').AsInteger := id;
  40. ParamByName('numero').AsInteger := numero;
  41. ParamByName('importe').AsFloat := importe;
  42. ParamByName('fechae').AsString := fechae;
  43. ParamByName('horae').AsString := horae;
  44. ParamByName('idsucursal').AsInteger := ids;
  45.  
  46. ParamByName('idcliente').AsInteger := idcliente;
  47. ParamByName('tipo').AsString := tipo;
  48. ParamByName('efectivo').AsFloat := efectivo;
  49. ParamByName('vuelto').AsFloat := vuelto;
  50. ExecSQL();
  51. end;
  52.  
  53. // Tratamiento de detalles
  54.  
  55. detalles.Open;
  56. detalles.first;
  57.  
  58. while not detalles.eof do // recorre el dataset
  59. begin
  60. qVenta.Close;
  61.  
  62. qVenta.ParamByName('idt').AsInteger := id;
  63.  
  64. qVenta.ParamByName('idp').AsInteger := detalles.FieldByName('idp')
  65. .AsInteger;
  66.  
  67. qVenta.ParamByName('cantidad').AsFloat :=
  68. detalles.FieldByName('cantidad').AsFloat;
  69.  
  70. qVenta.ParamByName('preciou').AsFloat :=
  71. detalles.FieldByName('precio').AsFloat;
  72.  
  73. qVenta.ExecSQL();
  74.  
  75. detalles.Next;
  76. end;
  77. // fin tratamiento detalles
  78.  
  79. SUCURSAL.CommitFreeAndNil(tr);
  80. end;
  81.  
  82. except
  83. SUCURSAL.RollbackFreeAndNil(tr);
  84. end;
  85. finally
  86. SUCURSAL.Close;
  87. end;
  88. end;
  89.  
  90. end.

Como ves es una tabla con un único campo que siempre tendrá un solo registro, si llamamos la función por fuera de la transacción jamás chocarán pedidos desde diferentes clientes, puesto que el tiempo que demora en incrementar el número son milésimas de segundo, en realidad esta implementación actúa de la misma manera que un generador en Firebird. 

 

Prueba y me cuentas.

 

Saludos. 


  • 0

#12 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 posts

Posted 13 May 2015 - 04:36 PM

ok lo probare.. pero lo que si que debo tener un metodo como este para cada relacion en la base de datos en la cual tenga este caso? Deberia estar solucionado esto por parte de los motores de base de datos :tongue: .jja

 

Gracias


  • 0

#13 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2137 posts

Posted 13 May 2015 - 05:56 PM



ok lo probare.. pero lo que si que debo tener un metodo como este para cada relacion en la base de datos en la cual tenga este caso? Deberia estar solucionado esto por parte de los motores de base de datos :tongue: .jja

 

Gracias

 

La decisión de declarar un campo autoincremental es tuya y solo tuya, de tus conocimientos sobre el motor y las exigencias de tu diseño dependerá si los usas o no. Personalmente jamás uso autoincrementales para claves primarias de tablas maestras. Por algo será que algunos motores no tienen esa opción directamente, por ejemplo en Firebird un campo autoincremental como tal no existe, en cambio cuenta con generadores que actúan en conjunción con un Trigger o con un Procedimiento almacenado, y su mecánica no es muy distinta a lo que te he planteado.

 

A lo largo de mis respuestas te he repetido que debe haber una forma en MYSQL de conocer el último valor insertado en un campo autoincremental,  si decides insistir con el campo autoincremental,  googleando he visto que hay funciones en MYSQL para eso, podrías implementar una función en Delphi que ejecute la función de MySQL y obtenga su valor.  Luego tu procedimiento de grabación debería seguir este orden:

 

- Declarar una variable de tipo entero.

- Iniciar la transacción.

- Iniciar la grabación del registro de la tabla maestra.

- Llamar la función que genera el ID y pasarla a la variable.

- Pasar el valor de la variable a cada registro de detalles y grabarlos.

- Finalizar transacción.

 

Saludos.


  • 0

#14 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 posts

Posted 14 May 2015 - 10:27 AM

ok muchas gracias por tu ayuda.. voy a implementar esa solucion porque no veo otra salida... pero te pregunto:

 

en la tabla de generador de id podria tener los ids de las otras tablas(donde se da el mismo caso): tu pones todos los ids en una sola(por ejemplo idpresupuesto para relacionarlo con su detalle?)


  • 0

#15 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2137 posts

Posted 14 May 2015 - 11:12 AM

ok muchas gracias por tu ayuda.. voy a implementar esa solucion porque no veo otra salida... pero te pregunto:

 

en la tabla de generador de id podria tener los ids de las otras tablas(donde se da el mismo caso): tu pones todos los ids en una sola(por ejemplo idpresupuesto para relacionarlo con su detalle?)

 

No hay ningún problema, hay dos opciones:

- O bien usas la tabla tal como está y te genera números únicos para cuantas tablas quieras (por supuesto quedan huecos entre tablas pero eso no es relevante).

- O creas otro campo en la tabla generadora para identificar la tabla para la que vas a generar (entonces habría que ajustar las sentencias de actualización y de obtención del valor en función de la tabla que hace la petición).

 

Si crees que tu aplicación es de muy alta concurrencia entonces es mejor curarse en salud y crear una tabla generadora por cada tabla maestra crítica, para evitar cuellos de botella.

 

No te preocupes, esta es una técnica muy común para generar números consecutivos (sin huecos) para campos diferentes a la clave primaria que así lo requieran, por ejemplo en la numeración de facturas, en cuyo caso la obtención de dicho número si debería  ir inmerso en una transacción.

 

En tu caso que solo necesitas generar claves primarias (no necesariamente consecutivas) no es necesario hacer la llamada dentro de la transacción, esto evitará bloqueos por inperceptibles que sean.

 

En cualquier caso es mucho más barato en términos de consumo de recursos consultar y  actualizar una tabla que tiene un solo campo y un solo registro que hacer un select max (id) o un select max(numero) a una tabla con 2 o 3 millones de registros. 

 

Saludos.

 

PD: Vuelvo y te repito esta es solo una forma de encarar el problema, si investigas más acerca del motor de DB muy seguramente encontrarás otras maneras de hacerlo, quizá otro compañero tenga otras experiencias al respecto.


  • 0

#16 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 posts

Posted 14 May 2015 - 01:22 PM

Comparto este enlace:

 

http://mysql.conclas...=LAST_INSERT_ID

 

donde justamente nombra el metodo que me recomendaste y lo compara con last_insert_id().

 

Saludos


  • 0




IP.Board spam blocked by CleanTalk.