entre Desarrolladores

Recibe ayuda de expertos

Registrate y pregunta

Es gratis y fácil

Recibe respuestas

Respuestas, votos y comentarios

Vota y selecciona respuestas

Recibe puntos, vota y da la solución

Pregunta

2votos

Como inserto el ID de una tabla en otro campo de la misma tabla?

Buen día comunidad,

Tengo una tabla llamada Caja que contiene los siguientes campos: idcaja (FK)(autoincrement), fechacaja(date),numerocaja(int), valorcaja (int), notacaja(varchar), idempleado1 (int).
Lo que busco es que el campo numerocaja tome el idcaja anterior le sume 1 y sea mi numero de caja actual, he intentado por last insert id pero no me registra el campo en la tabla una vez ejecuto el $_POST, dejo el código para saber si falta algo o estoy escribiendo mal el código.

$consulta= mysql_query("select LAST_INSERT_ID(numerocaja) as last from caja order by idcaja desc limit 0,1 ");
$numerocaja=mysql_fetch_array($consulta);
// registar los datos en tabla caja
$fechacaja= $_POST['fechacaja'];
$numerocaja= $numerocaja['last']+1;
$valorcaja= $_POST['valorcaja'];
$notacaja= $_POST['notacaja'];
$idempleado1= $_POST['idempleado1'];

$consulta= "insert into caja (fechacaja,numerocaja,valorcaja,notacaja,idempleado1) values ('$fechacaja','$numerocaja',$valorcaja','$notacaja','$idempleado1')";
$resultado = mysql_query($consulta);
mysql_close($conexion);

agradezco la ayuda que la comunidad me brinde con este caso.

cordial saludo,

German Ramirez

1voto

gramirezpi comentado

Buen día comunidad

realizando ajustes al codigo emplee el siguiente, ya como por si en algún momento lo tuviese que aplicar:

$consulta= mysql_query("select LAST_INSERT_ID (idcaja) as last from caja order by idcaja desc limit 0,1 ");
$rw=mysql_fetch_array($consulta);
$numerocaja= $rw['last']+1;
// registar los datos en tabla caja
$fechacaja= $_POST['fechacaja'];
$numerocaja= $_POST['numerocaja'];  
$valorcaja= $_POST['valorcaja'];
$notacaja= $_POST['notacaja'];
$idempleado1= $_POST['idempleado1'];

$consulta= "insert into caja (fechacaja,numerocaja,valorcaja,notacaja,idempleado1) values ('$fechacaja','$numerocaja',$valorcaja','$notacaja','$idempleado1')";
$resultado = mysql_query($consulta);
mysql_close($conexion);
?>

ahora muestra este error:

( ! ) Notice: Undefined index: numerocaja in C:\wamp\www\webdb\asignacioncaja1.php on line xx

como se soluciona ese error?,

cordial saludo,

German Ramírez

2votos

magarzon comentado

Supongo que esta respuesta la has puesto sin ver la mía, porque sigues teniendo el fallo que te indiqué en mi respuesta.

El mensaje de error es debido a que estás cogiendo 'numerocaja' de $_POST, y entiendo que ese parámetro no lo estás enviando en el POST

1voto

gramirezpi comentado

hola, pido disculpa porque realmente no habia visto la respuesta, voy a aplicar el consejo del código y comento nuevamente, gracias.

2votos

gramirezpi comentado

hola, ya aplique el código descrito en la respuesta pero me dice: "Error en insert", la verdad quede perdido.
no se donde tendre el error modifique así:

$consulta = "insert into caja (fechacaja,valorcaja,notacaja,idempleado1) values ('$fechacaja','$valorcaja','$notacaja','$idempleado1')";
$resultado= mysql_query($consulta);
if (TRUE === mysql_query($consulta)) {
   $update = "UPDATE caja SET numerocaja = id WHERE id = LAST_INSERT_ID(idcaja)";
   if (!mysql_query($update)) {
      echo 'Error en update';
   }
} else {
  echo 'Error en insert';
}
$resultado= mysql_query($consulta);
mysql_close($conexion);

pero la verdad atenderé muy bien el consejo mejor elimino ese campo numerocaja y me evito rascarme mas la cabeza,

1voto

magarzon comentado

Hola.

Puede ser porque llamas hasta tres veces a mysql_query con la consulta y tienes alguno de los campos como índice único, o puede ser otro error.

Para saberlo, sustituye el echo 'Error en insert'; por echo mysql_error();

1voto

gramirezpi comentado

hola y gracias por la respuesta y consejos; empezé por el consejo de magarzon donde me dice que cambie el error al insert por mysql_error(); al hacerlo me sale lo siguiente: "Unknown column 'id' in 'where clause'", creo que traducido busca decir que desconoce la columna 'id'; ademas inserta los datos pero en 'numerocaja' registra NULL; además me triplica los datos me explico me ingresa 3 veces el mismo dato.

2votos

magarzon comentado

Te triplica los datos y te pone null porque has puesto 3 veces la llamada a mysql_query, ya te lo dije en otro comentario.

Y el error te lo da porque puse id pensando que así se llamaba tu campo en la tabla, pero ahora veo que se llama idcaja, cámbialo y te debería funcionar.

1voto

gramirezpi comentado

magarzon buenos dias,

ya los cambie por idcaja y sigue presentando la misma falla, ya elimine los mysql_query y deje solo 1, pero la falla persiste, pensando a futuro quiero utilizar mejor el campo con la siguiente opción: quiero en un inicio decirle a mi sistema que me inicie en equis numero y que de ahi se autoincremente, como debo hacerlo debo crear otra tabla o como debo proceder?, gracias de antemano

3 Respuestas

2votos

magarzon Puntos30650

Como dijo Jack el Destripador, vayamos por partes:

La función LAST_INSERT_ID() (así, sin el numerocaja que pones como parámetro, que no es necesario) devuelve el último id generado por una función INSERT (o UPDATE en casos específicos), PERO solo si ese INSERT ha sido generado en la misma conexión (y además solo si la tabla tiene un id AUTOINCREMENT). Cada vez que haces una petición a tu PHP, se abre una conexión nueva (en realidad es posible utilizar un pool de conexiones, que se reutilizarían, pero te puedes encontrar con el mismo problema), y por tanto al ser la consulta el primer comando que se ejecuta, siempre te va a dar 0 o null, porque no ha habido un INSERT previo (en la misma conexión).

Una vez aclarado esto, seguimos.

Entiendo que lo que quieres es que el numerocaja sea igual al id del último registro almacenado+1... ¡PERO ESO ES YA EL PROPIO ID DEL REGISTRO QUE ESTÁS INTENTANDO INSERTAR!. ¿Por qué no utilizas el propio id como numerocaja?

De todas formas, si por algún motivo extraño quisieras duplicar la información del id en el campo numerocaja, lo podrías hacer haciendo primero un insert y luego un update del campo numerocaja donde ya podrías utilizar la función LAST_INSERT_ID(), porque te dará el id del registro que has insertado, pero vamos, que lo veo una pérdida de tiempo y espacio.

Para terminar, por favor, dejad de utilizar la librería mysql de php, está obsoleta desde la versión 5.5.0, utilizad mysqli.

1voto

gramirezpi comentado

hola, gracias por la respuesta y orientación, la verdad la usé así porque no quería depender del id, desde un principio lo pensé como lo recomienda lo cual ayudaría ahorrar en código y muchas cosas mas; como lo ví en una base de datos que baje lo intente aplicar pero no dá o no sé que paso hago mal; ya que el código lo combinan con ajax y js y la verdad no tengo mucho conocimiento de esos lenguajes; ahora entiendo porque no me registra el dato o a veces salia el null o el 0; aplicaré el consejo sin embargo como aplicaría el INSERT y luego el UPDATE, me puedes escribir un ejemplo en codigo el cual sería más claro para mí, gracias.

2votos

magarzon comentado

Aunque sigo sin entender el motivo, sería así (usando mysql y no el recomendado mysqli, para no liarte más):

$insert = "INSERT INTO (fechacaja,valorcaja,notacaja,idempleado1) VALUES ('$fechacaja','$valorcaja','$notacaja','$idempleado1')";

if (TRUE === mysql_query($insert)) {
   $update = "UPDATE caja SET numerocaja = id WHERE id = LAST_INSERT_ID()";
   if (!mysql_query($update)) {
      echo 'Error en update';
   }
} else {
  echo 'Error en insert';
}

1voto

gramirezpi comentado

hola magarzon
le comparto la solución al codigo de acuerdo a su orientación:

$fechacaja= $_POST['fechacaja'];
$valorcaja= $_POST['valorcaja'];
$notacaja= $_POST['notacaja'];
$idempleado1= $_POST['idempleado1'];

$consulta = "insert into caja (fechacaja,valorcaja,notacaja,idempleado1) values ('$fechacaja','$valorcaja','$notacaja','$idempleado1')";
if (TRUE === mysql_query($consulta)) {
   $numerocaja= "UPDATE caja SET numerocaja = numerocaja where numerocaja = last_insert_id(idcaja)+1";
   if (!mysql_query($numerocaja)) {
      echo 'Error en update';
   }
} else {
  echo 'Error en insert';
}
mysql_close($conexion);

funciona bien, mil gracias.

1voto

gramirezpi comentado

hola magarzon

publico el codigo correcto:

$fechacaja= $_POST['fechacaja'];
$valorcaja= $_POST['valorcaja'];
$notacaja= $_POST['notacaja'];
$idempleado1= $_POST['idempleado1'];

$consulta = "insert into caja (fechacaja,valorcaja,notacaja,idempleado1) values ('$fechacaja','$valorcaja','$notacaja','$idempleado1')";
if (TRUE === mysql_query($consulta)) {
   $update = "UPDATE caja SET numerocaja = LAST_INSERT_ID(idcaja)";
   if (!mysql_query($update)) {
      echo 'Error en update';
   }
} else {
  echo 'Error en insert';
}
mysql_close($conexion);

sin querer en el anterior estaba dando mal el resultado pero este si funciona y funciona bien, gracias por su orientación

1voto

magarzon comentado

Te falta una cosa en el UPDATE, fíjate en mi respuesta, si no le pones una cláusula where idcaja = last_insert_id(), te va a actualizar todos los registros

1voto

gramirezpi comentado

hola magarzon
de acuerdo a su observación, aplique así el codigo:

if (TRUE === mysql_query($consulta)) {
   $update = "UPDATE caja SET numerocaja = LAST_INSERT_ID(idcaja) WHERE idcaja = idcaja ";
   if (!mysql_query($update)) {
      echo 'Error en update';
   }
} else {
  echo 'Error en insert';
}

quisiera saber si está bien, ya que al intentar colocarlo en el orden que me sugieres al inicio de la respuesta el campo me sale null, pero asi como lo escribo aqui funciona bien, quedo atento.

2votos

Leonardo-Tadei Puntos227320

Hola @gramirezpi,

como dice @magarzon, si el número de cierre de caja coincidirá con el ID, no se justifica tener otro campo para este dato.

Hay casos en que se justifica, como por ejemplo cuando el usuario determina que va por el cierre 200 cuando pone en marcha el software, en cuyo caso el ID del primer registro será 1 pero el número de cierre debe ser 200.

Para estos casos en que el valor de la columna puede ser distinto del ID, la query que te hace falta es esta:

$consulta= "INSERT INTO caja
SET fechacaja = '$fechacaja',
numerocaja = ( SELECT MAX(numerocaja) FROM caja AS C )+1,
valorcaja = $valorcaja,
notacaja = '$notacaja',
idempleado1 = '$idempleado1';";

Te cambié la sintaxis de (campos) values() a SET, para que sea más claro el valor que toma el número de caja, que es el máximo existente más 1, y que no tiene relación con el ID.

Prestá especial atención al 'caja AS C de la subquery, porque sin eso da un error: la subquery necesita un alias para que no sea tratada como la propia tabla a insertar, ya que de otra manera da error.

Saludos cordiales!

0voto

magarzon comentado

El problema con esta solución es que dos peticiones concurrentes pueden insertar el mismo número de caja, pues ambas van a tomar el mismo registro como referencia para el max antes de insertar

0voto

Leonardo-Tadei comentado

Hola @magarzon,

interesante planteo!

En realidad, al RDBMS garantizar las ACID, como el INSERT es una instrucción atómica y se comportará como una transacción, la concurrencia no debería dar problemas.

Con esta línea de pensamiento, ejecutar un UPDATE posterior sería un escenario semejante en un ambiente de acceso concurrente como es la web.

Se puede afirmar que salvo que el sitio tenga cientos de visitas por segundo, la solución que propongo funciona como se espera, además de que hace independiente el valor del númoero de la caja del del ID.

Saludos cordiales!

0voto

magarzon comentado

Hola @Leonardo-Tadei

Aunque el insert sea una instrucción atómica, al tener esa subquery, y además sobre la misma tabla, no se comporta como una transacción a menos que se lo indiques con START TRANSACTION, por lo que una solución como la tuya puede producir en el mejor de los casos números de caja duplicados, en el peor deadlocks, según como esté configurada la base de datos.

Y no hace falta cientos de visitas por segundo, se puede conseguir el deadlock/repetición de números con un par de threads haciendo varias peticiones.

En la solución que yo indiqué, el UPDATE posterior es thread safe, porque el LAST_INSERT_ID() es un contador por conexión, no compartido entre conexiones/threads.

Si lo que quieres es actualizar el número de caja con el select max, mete el insert en una transacción para evitar problemas. Eso sí, el rendimiento bajaría, pero si no es una web con mucha carga es asumible. Para alto rendimiento sería mejor otras opciones, como tener un servicio generador de números de caja únicos, ya sea autoincrementados, uuid, etc.

0voto

Leonardo-Tadei comentado

Hola @magarzon,

la solución que propongo es para no usar el campo ID, que puede no tener sentido si su valor es repetido en numerocaja. Si ID y numerocaja siempre tuvieran el mismo valor, parece claro que uno de los 2 sobra.

Por otra parte, si bien tu propuesta es thread safe, al ser
PHP un lenguaje que no soporta hilos de ejecución, no afectaría en nada en el esquema de la subquery().

El manual de MySQL acota el ámbito de uso de LAST_INSERT_ID().

En fin: mi idea era desacoplar el valor del ID del de numcaja. Tenemos 4 o 5 softwares que hace esto funcionando hace algunos años sin problemas. Si bien en teoría la solución tiene límites, en la práctica no los hemos encontrado, incluso en aplicaciones que tienen 10 o 20 mil visitas diarias.

Saludos cordiales!

0voto

magarzon comentado

Al indicar que mi solución era thread safe, me refería a thread safe respecto a la base de datos, no respecto al PHP.

Es decir, me refiero a que dos peticiones concurrentes que hagan el insert y luego llamen a LAST_INSERT_ID van a obtener cada una el id de su propia operación insert, porque cada conexión/thread de la base de datos tiene su propio "contador" de ids insertados.

Y que los problemas de concurrencia en determinadas circunstancias sean improbables no quiere decir que sean imposibles, pero debe ser porque yo estoy acostumbrado a programar sistemas que tienen esas 10 o 20 mil visitas, pero al segundo, no al día. Es mejor pensar a lo grande y evitar problemas.

0voto

Leonardo-Tadei comentado

Totalmente de acuerdo!

yo apuntaba al "suficientemente bueno" como una solución razonable. Acá desarrollamos sobre todo software para empresas y extranet, por lo que la cantidad de visitas no es tan grande. Además usamos siempre modelos multitenant que minimizan el acceso concurrente a los datos.

Cómo enfocarías en este escenario de miles de visitas por segundo el poder desacoplar el valor del ID del valor numerocaja +1 ? Solo pondrías una query similar a la que propongo en una transacción o le harías algo más?

0voto

magarzon comentado

La solución a adoptar en el caso de webs con mucho tráfico depende mucho de lo que realmente se requiera. El emplear transacciones puede impactar bastante en situaciones de carga alta.

Habría que tener en cuenta:

  • Si tiene que estar relacionado con algún otro dato de la base de datos/registro a insertar o no
  • Si tiene que tener algún tipo de formato/restricción o simplemente con ser un integer autoincrementado vale

Por eso es por lo que hablaba de algún servicio/método independiente de la base de datos que te diera esa numeración.

Si simplemente queremos tener un id único, con una función como uniqid de PHP te puede valer.
Si queremos un valor autoincrementado, podemos utilizar la función microtime que nos da el timestamp al microsegundo (o incluso hay opciones para obtenerla al nanosegundo), o incluso tener una tabla con solo un campo id autoincrementado y utilizar el LAST_INSERT_ID, en términos de velocidad es mucho más eficiente que cualquiera de las otras soluciones (insert-update, insert-select max), lo único que tienes una tabla más ocupando algo de espacio (en ocasiones es una solución válida).

En un caso concreto nosotros hemos utilizado un servicio que genera UUIDs únicos y criptográficamente seguros (no con uniqid, porque necesitábamos algo de seguridad), y para no tener que ralentizar la inserción por la generación del uuid el mismo servicio se encargaba de ir generándolos previamente y depositándolos en un Redis, de donde obtenerlos es bastante fácil y rápido.

Hay mil opciones, y todo depende de los requisitos.

1voto

gramirezpi comentado

hola y gracias por la respuesta y consejos; empezé por el consejo de magarzon donde me dice que cambie el error al insert por mysql_error(); al hacerlo me sale lo siguiente: "Unknown column 'id' in 'where clause'", creo que traducido busca decir que desconoce la columna 'id'; ademas inserta los datos pero en 'numerocaja' registra NULL; además me triplica los datos me explico me ingresa 3 veces el mismo dato.

1voto

gramirezpi comentado

Hola leonardo,
apliqué tu consejo y aunque aparentemente no muestra error el numerocaja me sale NULL,
no se porque lo toma así?,
Debido a estos inconvenientes y pensando en futuros software, como puedo hacer o que es lo mas aconsejable para uno indicarle al programa que de 'x' numero se inicie la numeración y de ahí siga incrementandose, como debo hacerlo? se hace necesario crear otra tabla para este fin?, que me aconsejan?

1voto

Leonardo-Tadei comentado

Hola @gramirezpi,

la query que te indico no tiene ningún campo llamado ID para que te de ese error. Podrías copiar y pegar acá la consulta que tiene el INSERT luego de que la cambiaste como te indico?

1voto

gramirezpi comentado

Hola Leonardo,

mira el codigo:
$fechacaja= $_POST['fechacaja'];
$valorcaja= $_POST['valorcaja'];
$notacaja= $_POST['notacaja'];
$idempleado1= $_POST['idempleado1'];

$consulta= "INSERT INTO caja
SET fechacaja = '$fechacaja',
numerocaja = ( SELECT MAX(numerocaja) FROM caja AS C )+1,
valorcaja = $valorcaja,
notacaja = '$notacaja',
idempleado1 = '$idempleado1';";

$resultado= mysql_query($consulta);
mysql_close($conexion);

1voto

gramirezpi comentado

Leonardo buen día
Mira encontré este fragmento de código el cual adapte para intentar hacer lo que quiero:
$sql=mysql_query("select LAST_INSERT_ID(idcaja) as numerocaja from caja");
$rw=mysql_fetch_array($sql);
$numero_factura=$rw['numerocaja']+1;
ahora mi duda es como hago para que lo inserte, porque hasta ahí se que hace una operación pero como hago para $_POST?

-1voto

gramirezpi comentado

hola leonardo
comparto la solución a este problema de acuerdo a la observación que dió magarzon.

$fechacaja= $_POST['fechacaja'];
$valorcaja= $_POST['valorcaja'];
$notacaja= $_POST['notacaja'];
$idempleado1= $_POST['idempleado1'];

$consulta = "insert into caja (fechacaja,valorcaja,notacaja,idempleado1) values ('$fechacaja','$valorcaja','$notacaja','$idempleado1')";
if (TRUE === mysql_query($consulta)) {
   $numerocaja= "UPDATE caja SET numerocaja = numerocaja where numerocaja = last_insert_id(idcaja)+1";
   if (!mysql_query($numerocaja)) {
      echo 'Error en update';
   }
} else {
  echo 'Error en insert';
}
mysql_close($conexion);

por fin funcionó, ahora tengo una duda como puedo crear una propia numeración y no depender de un id con autoincremento?

1voto

gramirezpi comentado

hola leonardo
el anterior codigo presentaba error, pero este si es el correcto y eliminó todos los null.

$fechacaja= $_POST['fechacaja'];
$valorcaja= $_POST['valorcaja'];
$notacaja= $_POST['notacaja'];
$idempleado1= $_POST['idempleado1'];

$consulta = "insert into caja (fechacaja,valorcaja,notacaja,idempleado1) values ('$fechacaja','$valorcaja','$notacaja','$idempleado1')";
if (TRUE === mysql_query($consulta)) {
   $update = "UPDATE caja SET numerocaja = LAST_INSERT_ID(idcaja)";
   if (!mysql_query($update)) {
      echo 'Error en update';
   }
} else {
  echo 'Error en insert';
}
mysql_close($conexion);

gracias por su ayuda.

1voto

Leonardo-Tadei comentado

Hola @gramirezpi,

para poder crear tu propia numeración de los números de caja, tendrías que implementar mi solución, que no usar el LAST_INSERT_ID()...

Es la query que te indico al principio de esta respuesta.

Para autonumerar un campo, hay que partir de un primer valor, ya que la tabla vacía fallaría con esa query. Se puede hacer que la subquery esté en un IF y asigne un valor inicial la primera vez, o podés partir de un registro agregado a mano con el valor inicial.

Saludos cordiales

1voto

gramirezpi comentado

hola leonardo
mira finalmente y atendiendo la sugerencia de magarzon, el codigo final quedo así:

if (TRUE === mysql_query($consulta)) {
   $update = "UPDATE caja SET numerocaja = LAST_INSERT_ID(idcaja) WHERE idcaja = idcaja ";
   if (!mysql_query($update)) {
      echo 'Error en update';
   }
} else {
  echo 'Error en insert';
}

hasta el momento funciona sin problema, no duplica ni triplica y todo esta correctamente.

1voto

Leonardo-Tadei comentado

Me alegra!

Cuando te haga falta mantener tu propia numeración de las cajas, consultá mi primer respuesta a esta pregunta.

Saludos cordiales!

1voto

gramirezpi Puntos390

Hola leonardo

le comparto la solución al codigo, lo hize con la observación que dejo magarzon:

$fechacaja= $_POST['fechacaja'];
$valorcaja= $_POST['valorcaja'];
$notacaja= $_POST['notacaja'];
$idempleado1= $_POST['idempleado1'];

$consulta = "insert into caja (fechacaja,valorcaja,notacaja,idempleado1) values ('$fechacaja','$valorcaja','$notacaja','$idempleado1')";
if (TRUE === mysql_query($consulta)) {
   $numerocaja= "UPDATE caja SET numerocaja = numerocaja where numerocaja = last_insert_id(idcaja)+1";
   if (!mysql_query($numerocaja)) {
      echo 'Error en update';
   }
} else {
  echo 'Error en insert';
}
mysql_close($conexion);

2votos

magarzon comentado

Esta solución no te va a funcionar, no tiene ningún sentido, en el UPDATE estás estableciendo el valor de un campo a sí mismo (set numerocaja=numerocaja) y el where nunca se va a dar, ya que estás intentando actualizar un registro que no tiene el número de caja asignado aún

Por favor, accede o regístrate para responder a esta pregunta.

Otras Preguntas y Respuestas


...

Bienvenido a entre Desarrolladores, donde puedes realizar preguntas y recibir respuestas de otros miembros de la comunidad.

Conecta