Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Firebird e Interbase (https://www.clubdelphi.com/foros/forumdisplay.php?f=19)
-   -   Relación de tablas con llaves foráneas (https://www.clubdelphi.com/foros/showthread.php?t=45493)

egostar 04-07-2007 22:04:11

Relación de tablas con llaves foráneas
 
Hola amigos,

Espero poder ser claro con algunas dudas que tengo.

Estoy creando una relación de tablas usando llaves foráneas.

Uso Firebird 2.0 y componentes IBX en Turbo Delphi

Las tablas que tengo, sus llaves primarias (PK) y sus llaves foráneas (FK) son las siguientes:

RECTORIAS


PK ID_Rectoria VARCHAR(3)
Nombre VARCHAR(30)

DIVISIONES

FK PK ID_Rectoria VARCHAR(3)
PK ID_Division VARCHAR(3)
Nombre VARCHAR(30)

DEPARTAMENTOS

FK PK ID_Rectoria VARCHAR(3)
FK PK ID_Division VARCHAR(3)
PK ID_Departamento VARCHAR(3)
Nombre VARCHAR(30)

SECCIONES

FK PK ID_Rectoria VARCHAR(3)
FK PK ID_Division VARCHAR(3)
FK PK ID_Departamento VARCHAR(3)
PK ID_Seccion VARCHAR(3)
Nombre VARCHAR(30)

Intento con esta relación de tablas generar agrupaciones de tipo organizacional.

Nota: Uso VarChar(3) ya que requiero que los datos tengan la forma:

RECTORIA+DIVISION+DEPARTAMENTO+SECCION
001+001+001+001

Preguntas:

¿Están bien creadas las relaciones y llaves?

¿Como generar automáticamente un consecutivo 001-002-003 en los campos dentro de la base de datos (con un procedimiento almacenado o con un Disparador)? Por ejemplo:

Cuando presiono el boton de Agregar en RECTORIA

RECTORIA = 001+

Cuando agrego una DIVISION y selecciono una RECTORIA, genere el siguiente número para la DIVISION

DIVISION = RECTORIA 001+

Cuando agrego una DEPARTAMENTO y selecciono una RECTORIA y una DIVISION, genere el siguiente número para el DEPARTAMENTO

DEPARTAMENTO = RECTORIA DIVISION 001+

Cuando agrego una SECCION y selecciono una RECTORIA una DIVISION y un DEPARTAMENTO, genere el siguiente número para el DEPARTAMENTO

SECCION = RECTORIA DIVISION DEPARTAMENTO 001+

Espero haber sido claro con mis desorden mental.:eek:

Gracias anticipadas.

Salud OS.

gabrielkc 04-07-2007 22:14:18

Una rectoría tiene un valor único, cuando creas una division se crea con un valor único le agregas la llave de la rectoría a la que pertenece hasta ahi va bien.

El problema es cuando creas un departamento

DEPARTAMENTO = RECTORIA DIVISION 001+

el departamento tiene un valor único el cual debes relacionar con una división, la rectoría en este caso sobra dado que sabiendo la division puedes saber la Rectoría, estas redundando datos.

Por lo tanto haces lo mismo cuando creas una división

SECCION = RECTORIA DIVISION DEPARTAMENTO 001+


con el valor del departamento al que pertenece, puedes obtener la división y con esta la rectoría.

egostar 04-07-2007 22:24:22

Si, de hecho eso mismo hago ahora mismo, pero debo capturar el valor del concepto correspondiente

RECTORIA
DIVISION
DEPARTAMENTO
SECCION


El problema que le veo es que la captura requiere de saber cual es el último dato ingresado y no quiero que sea un campo autoincrementable (cosa que creo no puede ser porque son campos VARCHAR).

Aqui muestro el bosquejo del módulo que estoy creando.



En realidad lo único que quiero que se capture es el nombre de la SECCION en este caso.

Salud OS.

Edito: Además, quiero que esto lo haga la base de datos usando un Procedimiento almacenado o un Disparador, bueno, así lo he soñado, no quisiera hacerlo por código, que es otra alternativa si no hay una solución a esta duda.

gabrielkc 04-07-2007 22:34:42

mmm y si llamas un query con

SELECT MAX(ID_RECTORIA),NOMBRE FROM RECTORIA GROUP BY NOMBRE

y luego en el combo (en el cual supongo cargas los nombres de las rectorias, divisiones y departamentos), haces:

ComboRectoria.ItemIndex:=ComboRectoria.Items.IndexOf(Query.FieldByName('NOMBRE').AsString));

y obviamente lo mismo para división y departamento???

egostar 04-07-2007 22:44:11

Si gracias, con código es una opción que tengo contemplada como última opción.

He creado el siguiente procedimiento almacenado:

Código SQL [-]
begin
  /* Procedure Text */
  FOR SELECT seccion FROM SECCIONES
     WHERE RECTORIA = :c_rectoria and DIVISION = :c_division and DEPARTAMENTO = :c_depto
     INTO :c_seccion DO
  begin
    suspend;
  end
end

Si me funciona, pero me da el primer dato, lo que quiero es si es posible que dentro de ese procedimiento obtener el último valor para esa comparación (where .....)

Gracias por la ayuda.

Salud OS.

egostar 04-07-2007 22:49:15

Bueno, usando tu Query hice esto en el procedimiento.

Código SQL [-]
begin
  /* Procedure Text */
  FOR SELECT max(seccion) FROM SECCIONES
     WHERE RECTORIA = :c_rectoria and DIVISION = :c_division and DEPARTAMENTO = :c_depto
     INTO :c_seccion DO
  begin
    suspend;
  end
end
Efectivamente me regresa el último dato.

Ahora solo es ver de que manera lo coloco en el campo de mi forma con el siguiente valor.

Muchas gracias.

Salud OS.

egostar 04-07-2007 23:29:51

Solo para complementar este hilo les dejo el complemento de código que me funcionó como queria.

Al seleccionar el departamento, paso los parametros al SP, calculo el siguiente valor y le doy el formato deseado '000'.

Código Delphi [-]
procedure TFEstructura.DBLookupComboBox6CloseUp(Sender: TObject);
var
  Seccion : string;
  SeccionInt: integer;
begin
  with DMEstructura do begin
     IBSPSecciones.Prepare;
     IBSPSecciones.ParamByName('C_RECTORIA').Value :=  IBRectorias.FieldByName('RECTORIA').Value;
     IBSPSecciones.ParamByName('C_DIVISION').Value := IBDivisiones.FieldByName('DIVISION').Value;
     IBSPSecciones.ParamByName('C_DEPTO').Value := IBDeptos.FieldByName('DEPARTAMENTO').Value;
     IBSPSecciones.ExecProc;
     //Valido si se encontró algún dato en caso contrario inicializo en cero.
     if IBSPSecciones.Params[0].Value <> null then 
        Seccion := IBSPSecciones.Params[0].Value
     else Seccion := '0';
     IBSPSecciones.UnPrepare;
     SeccionInt := StrtoInt(Seccion)+1;
     //Asigno el formato 00x a partir del valor entero.
     IBSecciones.FieldByName('SECCION').Value := Format('%.*d',[3,SeccionInt]);
  end;
  DBMemo4.SetFocus;
end;

No se si lo que hago esta bien o sea lo correcto, pero he visto en varios hilos que es bueno que quien haga el trabajo sea la base de datos, bueno, para eso me imagino existen los SP.

Espero que a alguien le sirva.

Salud OS.

Ivanzinho 05-07-2007 09:15:33

Si lo quieres hacer todo dentro de un procedimiento prueba lo siguiente :
Código SQL [-]
begin
  /* Procedure Text */
  //Obtenemos el campo sección como un entero
  FOR SELECT Cast(max(seccion) as integer) FROM SECCIONES
     WHERE RECTORIA = :c_rectoria and DIVISION = :c_division and DEPARTAMENTO = :c_depto
     INTO :c_seccionint DO
  begin
    //Si es nulo lo inicializamos a 0
    if (c_seccionint is null) then
      c_seccion = 0;
    
    //Aumentamos el contador
    c_seccionint = c_seccionint + 1;

    //Pasamos el campo a VarChar(3)
    c_seccion = Cast(c_seccionint as VarChar(3))

    //Comprobamos que el campo tenga siempre tres caracteres,
    //esto lo pongo porque creo que quieres que el campo tenga
    //el formato 001 y no 1. Si te vale la forma 1 olvidate del while.
    while length(c_seccion) < 3 do
       c_seccion = '0' || c_seccion;

    //Para finalizar con el campo c_seccion ejecutas la acción que
    //desees, un insert, update, ...
   
  end
end

Espero que te sirva

Un saúdo.

egostar 05-07-2007 20:08:57

Muchas gracias Ivanzinho, lo voy a probar y comento los resultados.

Salud OS.


La franja horaria es GMT +2. Ahora son las 22:31:48.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi