 |
Club Builder Foro de C++Builder en español
|
| Ver tema anterior :: Ver tema siguiente |
| Autor |
Mensaje |
ercea Ens

Registrado: 07 May 2007Mensajes: 48
|
Publicado: Lun 07 May, 2007 11:43 pm Asunto: ¿Cómo puedo actualizar una tabla a partir de una consulta? |
|
|
Buenas, ante todo quiero presentarme ya que soy nuevo y recien registrado ^^, mi nombre es Jesús.
He intentado usar la búsqueda pero mi problema es un poco raro de explicar y no sé cómo buscarla xD.
Vereis, tengo en un formulario (una gestión de clientes por ejemplo), en el que tengo un componente Tabla que tiene la tabla de clientes, su datasource apuntando a esta tabla y luego un grid para mostrar el contenido de dicha tabla.
A parte, tengo un formulario para la inserción/edición de dichos clientes que consta de varios dbEdits (según el atributo de la tabla) cuyos datasources apuntan a la tabla.
Ahora viene lo "chungo", tengo otro formulario para realizar búsquedas por si quiero o bien ver detalles sobre un determinado cliente, o bien editarlo. En este nuevo formulario, tengo un componente SQL (supuse que lo correcto sería para la búsqueda una consulta SQL), su datasource correspondiente, y un grid para mostrar los resultados de la consulta.
Ahora lo que quiero hacer, y no sé cómo hacerlo, es que, una vez tenga algún resultado, al señalar en el grid al cliente que me interesa ve/editar, mediante un botón, cargar el formulario 2º que antes os he hablado (el de inserción/edicion de clientes), cargando dichos datos en los dbedits de este formulario para poder editar el cliente y actualizarlo en la tabla clientes.
Hasta ahora lo que he conseguido ha sido intentos fallidos, ya que lo que hacía era copiar en los dbedits->Text el contenido de cada campo del componente SQL del formurario de búsqueda (dbedit->Text = SQL->FieldByName("Campo")->AsString). Pero claro, si en el formurario de gestion (el 1º de todos) tenía, por ejemplo, seleccionado al 2º cliente en el grid, pues en el formulario de edición, en principio me aparece los campos de la consulta SQL (lógico ya que lo "forcé" al poner dbEdit->Text = ...), pero al hacer click en cada dbedit... se actualiza y me pone lo que realmente está seleccionado en la tabla (no sé si me explico ^^, a mi me costó averiguar el por qué me ocurría este fenómeno xDD).
En fin, si alguien puede ayudarme en cómo puedo modificaren la tabla, la tupla que se obtiene mediante una consulta SQL le estaría muy agradecido.
saludos! y gracias por adelantado ^^
EDITO: Me ha surgido otra duda, ¿hay alguna manera de capturar la excepción "Key violation" para poder mostrar yo mi propio mensaje de error?, es para cuando por ejemplo inserte otro cliente con el mismo DNI, pues en vez de salir el mensaje "noseke "Key violation" ", pueda mostrar algo como "El DNI introducido ya está en la base de datos", que mucha peña por ver mensajes en inglés ya se cagan xDD |
|
| Volver arriba |
|
 |
jacko Master


Registrado: 03 Sep 2005Mensajes: 287Ubicación: Colombia
|
Publicado: Mar 08 May, 2007 12:05 am Asunto: |
|
|
Hola ercea
Quizas no te pueda ayudar en todo lo que preguntas pero hare lo posible...
Primero, el Key violation es un error que manda la Base de Datos, no Builder, entonces no se si se pueda coger por las excepciones de Builder. Copia el codigo del error que te sale e intenta buscar mas informacion sobre este mensaje en el fabricante del motor de la base de datos.
Ahora otra cosa, si es posible que el dato se te repita, y genere la violacion de llave primaria, pues tu tabla esta mal diseñada. La idea de la llave primaria es que nunca se repita este dato por nada del mundo. Y si en alguna oportunidad ese dato puede repetirse, pues simplemente no es una key.
Puedes revisar por ese lado y quizas te quites el Key Violation de raiz.
Con lo otro de las tablas y las sql, perdoname, pero no te entendi muy bien. Espera a ver si alguno de los mas versados en el tema te pueden dar una mano.
Gracias! _________________ Dios es real... a menos que se declare entero! |
|
| Volver arriba |
|
 |
ercea Ens

Registrado: 07 May 2007Mensajes: 48
|
Publicado: Mar 08 May, 2007 12:37 am Asunto: |
|
|
Gracias por responder jacko, pero si me salta la excepción de violacion de key... es porque la tabla está bien diseñada no?, quiero decir, tengo creada la tabla y como clave primaria tengo el dni (en este ejemplo), si ahora el usuario intenta meter un nuevo cliente cuyo dni ya existe, me salta dicha excepción. Lo que quiero es que el usuario vea otro mensaje de error que no sea esa excepcion con codigos (una creada por mi mismo) o poder "controlar" o "avisar" antes de que intente insertarlo en la tabla y salte la excepción, a lo mejor con mal diseñada te referías a esto no?, que sea el programa quien tenga que avisar en vez de la base de datos, en ese caso ¿cómo podría controlarlo?.
Sobre lo otro a ver qué pasa ^^, es ahora mi problema principal, la verdad que es difícil de explicar...
saludos! y gracias por responder |
|
| Volver arriba |
|
 |
Angel Master


Registrado: 15 Abr 2003Mensajes: 2311Ubicación: Toledo (España)
|
Publicado: Mar 08 May, 2007 7:53 am Asunto: |
|
|
Hola Jesús. Bienvenido al foro. Voy a tratar de explicarte como hago yo lo de, por ejemplo, el DNI. Yo tengo un formulario en el que voy capturando los datos personales.
Lo que hago es verificar en el evento OnExit del correspondiente DBEdit. Te pongo aquí el código que uso:
| Código: | qBusDni->SQL->Text = "SELECT * FROM 'Persona.db' WHERE Nif = :Dni AND Registro <> :Registro" |
| Código: | char cLetras[23][1] = {"T","R","W","A","G","M","Y","F","P","D","X","B","N","J","Z","S","Q","V","H","L","C","K","E"};
if (!fTablas->Persona->FieldByName("Nif")->AsString.IsEmpty())
{
cTemp = FormatFloat("#########", StrToInt(fTablas->Persona->FieldByName("Nif")->AsString));
fTablas->qBusDni->Close();
fTablas->qBusDni->UnPrepare();
fTablas->qBusDni->ParamByName("Dni")->AsString = cTemp;
fTablas->qBusDni->ParamByName("Registro")->AsInteger = fTablas->Persona->FieldByName("Registro")->AsInteger;
fTablas->qBusDni->Prepare();
fTablas->qBusDni->Open();
if (!fTablas->qBusDni->IsEmpty())
{
Mensaje("Este DNI corresponde a otra ficha:\r\n\r\nApellidos: " + fTablas->qBusDni->FieldByName("Apellidos")->AsString + "\r\n"
"Nombre: " + fTablas->qBusDni->FieldByName("Nombre")->AsString, 48);
fTablas->Persona->FieldValues["Nif"] = "";
DBEdit3->SetFocus();
return;
}
fTablas->Persona->FieldValues["Nif"] = cTemp;
if (UpperCase(fTablas->Persona->FieldByName("Nif")->AsString.SubString(1, 1)) != "X")
{
for (nItem = 1;nItem <fTablas>Persona->FieldByName("Nif")->AsString.Length(); nItem ++)
if (isalpha(fTablas->Persona->FieldByName("Nif")->AsString.SubString(nItem, 1).c_str()[0]))
{
fTablas->Persona->FieldValues["Nif"] = "";
Mensaje("No incluya la letra del NIF.", 48);
DBEdit3->SetFocus();
return;
}
Label30->Caption = AnsiString(cLetras[StrToInt(fTablas->Persona->FieldByName("Nif")->AsString) % 23][0]);
}
} |
Además, aprovecho para calcular la letra del NIF (Label30->Caption), que no guardo en la tabla.
El otro problema que planteas. Yo también uso un método similar: En el formulario principal (alta y/o edición de fichas) tengo los DBEdit conectados con la tabla correspondiente y en el de búsqueda unos cuantos TEdit, un DBGrid y la consulta SQL de búsqueda. Para localizar al ficha que he seleccionado de la consulta SQL simplemente hago un Locate en la tabla de un campo que sea único en ella:
| Código: | void __fastcall TfBuscar::DBGrid1DblClick(TObject *Sender)
{
TLocateOptions oBuscar;
oBuscar.Clear();
fTablas->Persona->Locate("Registro", qBusAfi->FieldByName("Registro")->AsInteger, oBuscar);
fBuscar->Close();
}
//--------------------------------------------------------------------------- |
El campo Registro está definido en la tabla Persona como INTEGER y es único para cada registro que hay en la tabla. _________________ Un saludo
Necesitamos tu ayuda: Envía AI al 27595 (Coste 1,20 euros + IVA) |
|
| Volver arriba |
|
 |
ercea Ens

Registrado: 07 May 2007Mensajes: 48
|
Publicado: Mar 08 May, 2007 2:24 pm Asunto: |
|
|
Angel muchísimas gracias, de verdad ^^, ya funciona correctamente la búsqueda ^^.
Con respecto a lo del DNI, he estado probando y me pasa una cosa. Como tengo un mismo formulario para insertar y editar clientes, pues si elijo a un cliente y quiero editarlo (y no cambio el dni), me salta la excepción de que dicho cliente ya existe como si una inserción quisiera hacer. Se me ocurrió la idea de que si lo que estoy editando es a un cliente pues cambiar el caption del boton de inserción por "editar" (por ejemplo), y si estoy insertando, cambiarlo por "Insertar" (por ejemplo). Así en la comprobación "if(!SQL_Clientes->IsEmpty())" le añado " && boton1->caption != "Editar"), salte la excepción solamente cuando estoy insertando nuevos clientes.
Pero claro, como chapú que es, tampoco lo resuelve del todo, ya que si por ejemplo tengo estos dos clientes:
123456 - Paco Garcia
345678 - jose luis Fernandez
Y ahora quiero editar el dni a jose luis fernandez ... si lo cambio por 123456 (que es Paco) pues me salta el "Key violation"... supongo que en estos casos ya no se puede hacer nada no?, o tambien tiene solución?
De todos modos muchas gracias por vuestra ayuda
PD: Permíteme una pregunta tonta ¿Cómo has podido poner esos botones en tu formulario?, el diseño es muy bueno, a mi me pone el botón gris ese feo y anticuado ^^
saludos!! |
|
| Volver arriba |
|
 |
jacko Master


Registrado: 03 Sep 2005Mensajes: 287Ubicación: Colombia
|
Publicado: Mar 08 May, 2007 3:06 pm Asunto: |
|
|
Hola a todos.
Podriamos hacer lo siguiente para intentar solucionar algunos inconvenientes.
Lo primero que debes hacer es tomar en variables los datos que el usuario ingresa.
Luego, hacer una busqueda en la base de datos si el DNI existe (que me imagino que es un numero de identificacion verdad?). En este momento nos salen dos opciones: que ya existe el DNI o que no exista.
Si no existe pues lo ingresamos a la base de datos sin problema. (INSERT INTO ....)
Si ya existe el DNI, entonces preguntamos si el usuario quiere editar ese registro y entonces editamos el resto de la informacion. (UPDATE ... SET....)
Pero si ya existe el DNI y no es para editar sino para insertar, entonces aqui es donde mandamos el mensaje de error.
Y listo! Todo controlado por nuestro codigo y sin esperar las Key Violation porque todas las posibilidades ya estan cubiertas.
Intentalo con esta logica y nos cuentas. Si necesitas algo de codigo me avisas.
Gracias! _________________ Dios es real... a menos que se declare entero! |
|
| Volver arriba |
|
 |
ercea Ens

Registrado: 07 May 2007Mensajes: 48
|
Publicado: Mar 08 May, 2007 4:11 pm Asunto: |
|
|
Gracias por tu respuesta jacko, me has dado una idea y ya está resuelto al final lo que he hecho ha sido añadir esto en el evento "OnExit" del dbEdit correspondiente al DNI:
| Código: | if(!SQL_Clientes->IsEmpty())
{
//Creamos un formulario modal para preguntar si se quiere editar o no en caso de que exista
Application->CreateForm(__classid(TfrmModalEdit), &frmModalEdit);
AnsiString Temp = "Ya existe un cliente con D.N.I. = \"" + edDNI->Text + "\"";
frmModalEdit->lblInfo->Caption = Temp;
frmModalEdit->ShowModal();
//Si el usuario responde que sí, pues mostramos dicho cliente en el formulario
//y ponemos la tabla en modo edición (en vez de inserción como estaba en un principio)
if(frmModalEdit->ModalResult == mrYes)
{
TLocateOptions Buscar;
Buscar.Clear();
frmGestClientes->dbClientes->Cancel();
frmGestClientes->dbClientes->Locate("clt_dni",SQL_Clientes->FieldByName("clt_dni")->AsString,Buscar);
frmGestClientes->dbClientes->Edit();
frmNuevoCli->cmdInsertarCli->Caption = "&Editar Cliente";
}
else
{
frmNuevoCli->edDNI->SetFocus();
}
|
Así ya va la cosa bien ^^, gracias por todo chicos, sois geniales
saludos! |
|
| Volver arriba |
|
 |
jacko Master


Registrado: 03 Sep 2005Mensajes: 287Ubicación: Colombia
|
Publicado: Mar 08 May, 2007 7:12 pm Asunto: |
|
|
Muy bien ercea.
Que bueno que te hayan servido nuestras ideas!
Gracias. _________________ Dios es real... a menos que se declare entero! |
|
| Volver arriba |
|
 |
ercea Ens

Registrado: 07 May 2007Mensajes: 48
|
Publicado: Vie 06 Jul, 2007 4:15 pm Asunto: |
|
|
Revivo este hilo para preguntar una duda sobre la función Locate. El tema e que ahora lo estoy usando en una tabla que tiene como CP, dos atributos. Entonces supongo que para que la función Locate sea efectiva tendría que pasarle dichos atributos no?, entonces ¿cómo puedo poner los parámetros de la función Locate para que pille dos atributos en vez de uno?.
Si no entendeis, en mi caso es una tabla "maquinas" que tiene como CP un número de serie y un nº de modelo (provisional, ya que realmente no sé si con el nº serie bastará), entonces si hago una búsqueda de la maquina con Nº serie = 1 y Nº mod = 2, para luego editarla, cuando haga Maquinas->Locate(...), no sé cómo poner los parámetros para que coja los dos atributos.
saludos y gracias por adelantado |
|
| Volver arriba |
|
 |
jacko Master


Registrado: 03 Sep 2005Mensajes: 287Ubicación: Colombia
|
Publicado: Vie 06 Jul, 2007 5:03 pm Asunto: |
|
|
Hola ercea.
Por preguntarte nada mas, por qué no utilizas sentencias SQL?
Con SQL haces la busqueda por los criterios que quieras. La verdad, uso muy poco las funciones de Buidler para buscar, ubicar, insertar, etc. sino que todo lo hago con SQL y me da mas flexibilidad.
No se tu que opinas?
Saludos! _________________ Dios es real... a menos que se declare entero! |
|
| Volver arriba |
|
 |
ercea Ens

Registrado: 07 May 2007Mensajes: 48
|
Publicado: Vie 06 Jul, 2007 5:16 pm Asunto: |
|
|
Esa fue mi primera idea xD, pero como funcionaba lo de Locate es lo que uso. ¿Cómo se haria con setencias SQL?.
Te pongo en situación: tengo un formulario para realizar la búqueda de máquinas, yo hago una búsqueda, sale los resultados en un grid (asociado a un datasource, y éste a un Query que es el que se encarga de hacer las consultas SQL para buscar), luego elijo una máquina de ese grid y le doy a un botón que crea un formulario "Editar Máquina" para editar la información, ahora lo que no sé es cómo le digo a la tabla "Máquinas" que seleccione la misma máquina que he seleccionado en el grid (ya que el grid está asociado al query no a la tabla) y muestre la info de la máquina que tengo seleccionada en el grid, y aquí es donde la lío ahora xD, con otras tablas usaba la función Locate pasandole la CP, que casualmente era un solo atributo, pero en este caso que son dos... no me vale (o no sé cómo se pondría)
saludos y gracias por responder  |
|
| Volver arriba |
|
 |
Angel Master


Registrado: 15 Abr 2003Mensajes: 2311Ubicación: Toledo (España)
|
Publicado: Vie 06 Jul, 2007 5:34 pm Asunto: |
|
|
A ver. Con Locate, según la ayuda de Builder:
| Código: | TLocateOptions Opts;
Opts.Clear();
Opts <<loPartialKey>Locate("Company;Contact", VarArrayOf(locvalues, 1), Opts); |
Con SQL:
| Código: | Query->Close();
Query->UnPrepare();
Query->SQL->Text = "SELECT FROM Mitabla WHERE Campo1 = :Campo1 AND Campo2 = :Campo2",
Query->ParamByName("Campo1")->AsString = <Valor1>;
Query->ParamByName("Campo2")->AsString = <Valor2>;
Query->Prepare();
Query->Open(); |
_________________ Un saludo
Necesitamos tu ayuda: Envía AI al 27595 (Coste 1,20 euros + IVA) |
|
| Volver arriba |
|
 |
Cesar C. Salazar Gonzalez Master


Registrado: 01 Oct 2002Mensajes: 2155Ubicación: San Cristóbal de Las Casas, Chiapas
|
|
| Volver arriba |
|
 |
Tor Master


Registrado: 22 Mar 2005Mensajes: 269Ubicación: obera, misiones, argentina
|
Publicado: Dom 08 Jul, 2007 4:11 am Asunto: |
|
|
hola ercea, creo que la solucion ya la tenes pero queria acotar algo, que tienes una guia detallada sobre la funcion Locate en el libro "la cara oculta de c++ builder" que no vas a tener problema para bajarlo de la red. con respecto a la funcion locate vas a encontrar varios ejemplos en la pagina 348. pero como decia la respuesta ya la tenes el ejemplo que te dio angel soluconaria tu problema con el locate  |
|
| Volver arriba |
|
 |
ercea Ens

Registrado: 07 May 2007Mensajes: 48
|
Publicado: Lun 09 Jul, 2007 5:25 pm Asunto: |
|
|
Gracias por vuestras respuestas, observando el libro de The Dark Side... (muy buen libro) he visto como buscar cuand ohay más de un atributo, pero no me funciona. El libro viene con este ejemplo:
| Código: |
Consideremos ahora que queremos localizar un empleado, dados el nombre y el apellido.
La instrucción necesaria es la siguiente:
tbEmpleados->Locate("LastName;FirstName",
VarArrayOf(ARRAYOFCONST((Apellido, Nombre))), TLocateOptions());
En primer término, hay que mencionar los nombres de ambas columnas en el primer parámetro, separadas por punto y coma. Después, hay que pasar los dos valores correspondientes como una matriz variante; la función VarArrayOf es útil para esta última misión. En este ejemplo, las variables Apellido y Nombre son ambas de tipo AnsiString, pero pueden pertenecer a tipos diferentes, en el caso más general. |
Pues bien, siguiendo elmismo esquema pongo lo siguiente:
| Código: |
frmMaquinas->dataMaquinas->Locate("maq_nserie;maq_nmod",VarArrayOf(ARRAYOFCONST(( SQLBusMaq->FieldByName("maq_nserie")->AsString, SQLBusMaq->FieldByName("maq_nmod")->AsString)),TLocateOptions());
|
dataMaquinas es el IBDataSet que accede a la tabla Maquinas y SQLBusMaq es el componente IBQuery para realizar las búsquedas. Pues el compilador me salta con el siguiente error:
| Código: | E2034 Cannot convert 'OpenArray<TVarRec>' to 'const Variant *'
E2342 Type mismatch in parameter 'Values' (wanted 'const Variant *', got 'OpenArray<TVarRec>') |
Por otra parte César he mirado tu enlace y este también (que casi querías hacer lo mismo que yo, solo que en vez de volver para editar, lo que hago es abrir otro formulario con dbedits, para editar la info; es decir, tenog un formulario "principal" simplemente con un grid mostrando todas las máquinas que hay, mas unos botones (nuevo, editar, etc), y según el botón un formulario con dbedits (cuando se quiere insertar/editar) o el formulario de búsqueda, que además de mostrar en el grid los resultados, hay un boton "Editar"):
https://cppbuilder.es/viewtopic.php?t=10542&highlight=formulario+busqueda+interbase
Pero no entiendo muy bien lo que se quiere decir, ¿quizás el error mio es utilizar el IBQuery en vez de otro componente (como IBDataSet)?
Aún así, seguiré buscando e informandome mejor xD
graicas a todos, saludos |
|
| Volver arriba |
|
 |
|
|
No puedes publicar temas nuevos en este foro No puedes responder a temas en este foro No puedes editar tus mensajes en este foro No puedes borrar tus mensajes en este foro No puedes votar en las encuestas de este foro
|
© 2002–2026 Club Builder · Funciona con phpBB.
|