Ir al contenido


Foto

Optimizar un codigo con querys


  • Por favor identifícate para responder
12 respuestas en este tema

#1 FGarcia

FGarcia

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 687 mensajes
  • LocationMéxico

Escrito 23 diciembre 2008 - 07:28

Por aqui solicitando ayuda para optimizar el codigo. Esta es la unidad del modulo de datos de la imagen que adjunto. El proposito es que en la stringgrid se vean los resultados de las consultas efectuadas segun el estado de los checkbox. ¡Funciona asi como esta! pero siento que el codigo es un absoluto cochinero y que se puede mejorar asi que acudo a ustedes por ideas para mejorarlo.



delphi
  1. unit UdmDatos;
  2.  
  3. interface
  4.  
  5. uses
  6.  SysUtils, Classes, DB, IBCustomDataSet, IBQuery, IniFiles;
  7.  
  8. //Declaro el tipo TGrupo
  9. type
  10.  TGrupo = array[1..6] of boolean;
  11.  
  12. type
  13.  TdmDatos = class(TDataModule)
  14.    qyGrupo1: TIBQuery;
  15.    qyGrupo2: TIBQuery;
  16.    qyGrupo3: TIBQuery;
  17.    procedure DataModuleCreate(Sender: TObject);
  18.  private
  19.    { Private declarations }
  20.    idx11,idx12,idx13,idx14,idx15,idx16: integer; //Numeros de bascula grupo1
  21.    idx21,idx22,idx23,idx24,idx25,idx26: integer; //Numeros de bascula grupo2
  22.    idx31,idx32,idx33,idx34,idx35,idx36: integer; //Numeros de bascula grupo3
  23.    procedure LeerGrupos;
  24.    procedure AsignaBasculaGrupo1;
  25.    procedure AsignaBasculaGrupo2;
  26.    procedure AsignaBasculaGrupo3;
  27.  public
  28.    { Public declarations }
  29.    Grupo1, Grupo2, Grupo3: TGrupo;
  30.    Cuantos1,Cuantos2,Cuantos3: integer;
  31.    Total1,Total2,Total3: double;
  32.    procedure SumarGrupo1;
  33.    procedure SumarGrupo2;
  34.    procedure SumarGrupo3;
  35.  end;
  36.  
  37. const
  38.  Archivo = 'Configura.ini';
  39.  
  40. var
  41.  dmDatos: TdmDatos;
  42.  
  43.  
  44. implementation
  45.  
  46. uses
  47.  UdmCnx;
  48.  
  49.  
  50. {$R *.dfm}
  51.  
  52. { TdmDatos }
  53.  
  54. //Al crear el modulo se ejecutan estos procedimientos
  55. procedure TdmDatos.DataModuleCreate(Sender: TObject);
  56. begin
  57.  LeerGrupos;
  58.  AsignaBasculaGrupo1;
  59.  AsignaBasculaGrupo2;
  60.  AsignaBasculaGrupo3;
  61.  SumarGrupo1;
  62.  SumarGrupo2;
  63.  SumarGrupo3;
  64. end;
  65.  
  66. //Leemos el ultimo estado de los checkbox el cual se guardo en un INI
  67. procedure TdmDatos.LeerGrupos;
  68. var
  69.  F: TiniFile;
  70. begin
  71.    F := TIniFile.Create(ExtractFilePath(Paramstr(0)) + Archivo);
  72.  try
  73.    //***************** grupo 1
  74.   Grupo1[1] := F.readbool('Grupo1', 'Bascula1', False);
  75.   Grupo1[2] := F.readbool('Grupo1', 'Bascula2', False);
  76.   Grupo1[3] := F.readbool('Grupo1', 'Bascula3', False);
  77.   Grupo1[4] := F.readbool('Grupo1', 'Bascula4', False);
  78.   Grupo1[5] := F.readbool('Grupo1', 'Bascula5', False);
  79.   Grupo1[6] := F.readbool('Grupo1', 'Bascula6', False);
  80.    //***************** grupo 2
  81.   Grupo2[1] := F.readbool('Grupo2', 'Bascula1', False);
  82.   Grupo2[2] := F.readbool('Grupo2', 'Bascula2', False);
  83.   Grupo2[3] := F.readbool('Grupo2', 'Bascula3', False);
  84.   Grupo2[4] := F.readbool('Grupo2', 'Bascula4', False);
  85.   Grupo2[5] := F.readbool('Grupo2', 'Bascula5', False);
  86.   Grupo2[6] := F.readbool('Grupo2', 'Bascula6', False);
  87.    //***************** grupo 3
  88.   Grupo3[1] := F.readbool('Grupo3', 'Bascula1', False);
  89.   Grupo3[2] := F.readbool('Grupo3', 'Bascula2', False);
  90.   Grupo3[3] := F.readbool('Grupo3', 'Bascula3', False);
  91.   Grupo3[4] := F.readbool('Grupo3', 'Bascula4', False);
  92.   Grupo3[5] := F.readbool('Grupo3', 'Bascula5', False);
  93.   Grupo3[6] := F.readbool('Grupo3', 'Bascula6', False);
  94.  finally
  95.    F.Free ;
  96.  end;
  97. end;
  98.  
  99. {Segun el estado de cada elemento del array (TRUE / FALSE)
  100.   asignamos un numero a los indices}
  101. procedure TdmDatos.AsignaBasculaGrupo1;
  102. begin
  103.  if Grupo1[1] then
  104.    idx11 := 1
  105.  else
  106.    idx11 := 0;
  107.  
  108.  if Grupo1[2] then
  109.    idx12 := 2
  110.  else
  111.    idx12 := 0;
  112.  
  113.  if Grupo1[3] then
  114.    idx13 := 3
  115.  else
  116.    idx13 := 0;
  117.  
  118.  if Grupo1[4] then
  119.    idx14 := 4
  120.  else
  121.    idx14 := 0;
  122.  
  123.  if Grupo1[5] then
  124.    idx15 := 5
  125.  else
  126.    idx15 := 0;
  127.  
  128.  if Grupo1[6] then
  129.    idx16 := 6
  130.  else
  131.    idx16 := 0;
  132. end;
  133.  
  134. {Segun el estado de cada elemento del array (TRUE / FALSE)
  135.  asignamos un numero a los indices}
  136. procedure TdmDatos.AsignaBasculaGrupo2;
  137. begin
  138.  if Grupo2[1] then
  139.    idx21 := 1
  140.  else
  141.    idx21 := 0;
  142.  
  143.  if Grupo2[2] then
  144.    idx22 := 2
  145.  else
  146.    idx22 := 0;
  147.  
  148.  if Grupo2[3] then
  149.    idx23 := 3
  150.  else
  151.    idx23 := 0;
  152.  
  153.  if Grupo2[4] then
  154.    idx24 := 4
  155.  else
  156.    idx24 := 0;
  157.  
  158.  if Grupo2[5] then
  159.    idx25 := 5
  160.  else
  161.    idx25 := 0;
  162.  
  163.  if Grupo2[6] then
  164.    idx26 := 6
  165.  else
  166.    idx26 := 0;
  167. end;
  168.  
  169. {Segun el estado de cada elemento del array (TRUE / FALSE)
  170.  asignamos un numero a los indices}
  171. procedure TdmDatos.AsignaBasculaGrupo3;
  172. begin
  173.  if Grupo3[1] then
  174.    idx31 := 1
  175.  else
  176.    idx31 := 0;
  177.  
  178.  if Grupo3[2] then
  179.    idx32 := 2
  180.  else
  181.    idx32 := 0;
  182.  
  183.  if Grupo3[3] then
  184.    idx33 := 3
  185.  else
  186.    idx33 := 0;
  187.  
  188.  if Grupo3[4] then
  189.    idx34 := 4
  190.  else
  191.    idx34 := 0;
  192.  
  193.  if Grupo3[5] then
  194.    idx35 := 5
  195.  else
  196.    idx35 := 0;
  197.  
  198.  if Grupo3[6] then
  199.    idx36 := 6
  200.  else
  201.    idx36 := 0;
  202. end;
  203.  
  204. {Ejecutamos la consulta. Proporcionamos como parametro el numero de bascula
  205. que se obtuvo en el procedure AsignarGrupoBascula}
  206. procedure TdmDatos.SumarGrupo1;
  207. begin
  208.  
  209.  with qyGrupo1 do
  210.    begin
  211.      close;
  212.      sql.Clear ;
  213.      sql.Add('SELECT COUNT(*) AS Pesadas, ' +
  214.              'SUM (peso) AS Total ' +
  215.              'FROM DATOS WHERE ((Bascula = :Bas1) OR (Bascula = :Bas2) OR ' +
  216.                                 '(Bascula = :Bas3) OR (Bascula = :Bas4) OR ' +
  217.                                 '(Bascula = :Bas5) OR (Bascula = :Bas6))');
  218.      Params.ParamByName('Bas1').Value := idx11;
  219.      Params.ParamByName('Bas2').Value := idx12;
  220.      Params.ParamByName('Bas3').Value := idx13;
  221.      Params.ParamByName('Bas4').Value := idx14;
  222.      Params.ParamByName('Bas5').Value := idx15;
  223.      Params.ParamByName('Bas6').Value := idx16;
  224.      open;
  225.    end;
  226.  
  227.  if not qygrupo1.IsEmpty then
  228.    begin
  229.      Cuantos1 := qyGrupo1.FieldValues['Pesadas'];
  230.      Total1 := qyGrupo1.FieldValues['Total'];
  231.    end;
  232. end;
  233.  
  234. {Ejecutamos la consulta. Proporcionamos como parametro el numero de bascula
  235. que se obtuvo en el procedure AsignarGrupoBascula}
  236. procedure TdmDatos.SumarGrupo2;
  237. begin
  238.  with qyGrupo2 do
  239.    begin
  240.      close;
  241.      sql.Clear ;
  242.      sql.Add('SELECT COUNT(*) AS Pesadas, ' +
  243.              'SUM (peso) AS Total ' +
  244.              'FROM DATOS WHERE ((Bascula = :Bas1) OR (Bascula = :Bas2) OR ' +
  245.                                 '(Bascula = :Bas3) OR (Bascula = :Bas4) OR ' +
  246.                                 '(Bascula = :Bas5) OR (Bascula = :Bas6))');
  247.      Params.ParamByName('Bas1').Value := idx21;
  248.      Params.ParamByName('Bas2').Value := idx22;
  249.      Params.ParamByName('Bas3').Value := idx23;
  250.      Params.ParamByName('Bas4').Value := idx24;
  251.      Params.ParamByName('Bas5').Value := idx25;
  252.      Params.ParamByName('Bas6').Value := idx26;
  253.      open;
  254.    end;
  255.  
  256.  if not qygrupo2.IsEmpty then
  257.    begin
  258.      Cuantos2 := qyGrupo2.FieldValues['Pesadas'];
  259.      Total2 := qyGrupo2.FieldValues['Total'];
  260.    end;
  261. end;
  262.  
  263. {Ejecutamos la consulta. Proporcionamos como parametro el numero de bascula
  264. que se obtuvo en el procedure AsignarGrupoBascula}
  265. procedure TdmDatos.SumarGrupo3;
  266. begin
  267.  with qyGrupo3 do
  268.    begin
  269.      close;
  270.      sql.Clear ;
  271.      sql.Add('SELECT COUNT(*) AS Pesadas, ' +
  272.              'SUM (peso) AS Total ' +
  273.              'FROM DATOS WHERE ((Bascula = :Bas1) OR (Bascula = :Bas2) OR ' +
  274.                                 '(Bascula = :Bas3) OR (Bascula = :Bas4) OR ' +
  275.                                 '(Bascula = :Bas5) OR (Bascula = :Bas6))');
  276.      Params.ParamByName('Bas1').Value := idx31;
  277.      Params.ParamByName('Bas2').Value := idx32;
  278.      Params.ParamByName('Bas3').Value := idx33;
  279.      Params.ParamByName('Bas4').Value := idx34;
  280.      Params.ParamByName('Bas5').Value := idx35;
  281.      Params.ParamByName('Bas6').Value := idx36;
  282.      open;
  283.    end;
  284.  
  285.  if not qygrupo3.IsEmpty then
  286.    begin
  287.      Cuantos3 := qyGrupo3.FieldValues['Pesadas'];
  288.      Total3 := qyGrupo3.FieldValues['Total'];
  289.    end;
  290. end;
  291.  
  292.  
  293.  
  294. end.



Como siempre les agradesco la atencion y ayuda que me puedan proporcionar.
  • 0

#2 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 23 diciembre 2008 - 07:50

Tendría que analizarlo bien para ver hasta que punto lo podría reducir. De forma rápida lo que veo es más recomendable emplear una matriz para tratar los grupos y las básculas.

Si no entiendo mal, cuentas con tres grupos y en cada grupo hay 6 básculas. Eso a mi ya de forma directa me está manifestando que se puede conseguir y tratar ambas cosas (grupos y básculas) como una matriz.

Ya estoy viendo que hay mucho código repetido. Tranquilamente se puede tener métodos como:



delphi
  1. procedure SumarGrupo(NroGrupo: integer);


y



delphi
  1. procedure AsignarBásculasDelGrupo(NroGrupo: integer);



También se podría acelerar la lectura desde el archivo ini.

Dame un tiempo y luego te digo como lo haría yo.

Saludos,

  • 0

#3 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 23 diciembre 2008 - 08:52

Pues ya le estoy metiendo mano al asunto, y hay algo que no veo muy claro...
¿Esas consultas SQL funcionan?
Porque veo que es siempre la misma, y no veo que se distinga de un grupo de otra. Es decir: no veo en la cláusula WHERE algo como (Grupo = 1) o (Grupo = 2).

Por lo que estoy comprendiendo, una vez que en tus arrays "grupo" queda cargada la lectura del archivo ini estableces como valor la posición i-ésima de tu array N-ésimo o cero a cada variable idxNi, siendo "N" el numero del grupo e "i" el de la báscula.

Veamos el ejemplo que tu expones:
Grupo[1] tendría lo siguiente: (true,true,false,false,false,false)
Grupo[2] tendría: (false,false,true,true,false,false)
Grupo[3]: (false,false,false,false,true,true)

Entonces, al traspasar los datos a las variables idx, las únicas diferentes a cero, tendremos esto:
idx11 = 1
idx12 = 2

idx23 = 3
idx24 = 4

idx35 = 5
idx36 = 6

Las respectivas consultas SQL quedarían entonces así:
Grupo 1:
(Bascula = 1) or (Bascula = 2) or (Bascula = 0) or (Bascula = 0) or (Bascula = 0) or (Bascula = 0)

Grupo 2:
(Bascula = 0) or (Bascula = 0) or (Bascula = 3) or (Bascula = 4) or (Bascula = 0) or (Bascula = 0)

Grupo 3:
(Bascula = 0) or (Bascula = 0) or (Bascula = 0) or (Bascula = 0) or (Bascula = 5) or (Bascula = 6)

Hay comparaciones redundantes por empezar. Pero ese no es el veradero problema. Supongamos que en realidad del grupo 1 deseamos leer la 3 y 4.
La consula final quedaría con éstas condiciones:
(Bascula = 0) or (Bascula = 0) or (Bascula = 3) or (Bascula = 4) or (Bascula = 0) or (Bascula = 0)

Como vez, igual a la que esperamos para el grupo 2.
Por tanto vuelvo a la pregunta del millón: ¿Cómo en la consulta SQL determinamos al grupo? No que se filtren los datos... ¡Vas a obtener los mismos datos!

O algo no estoy comprendiendo... sería bueno que aclares ese panorama.
Por lo pronto ya estoy reduciendo código.

Me gustaría que aclares bien como está estructuradas tus tablas.

EDITO:
Ha... tal vez el tema de los grupos no es por algo que represente alguna entidad o realidad física propia del dominio.
Creo que por grupo debería entender a que el usuario puede indicar como desea ver los resultados de 6 básculas.

Yo me estaba imaginando que se disponen de 18 básculas, agrupadas de a 6. ¿Son en realidad 6?
¿La finalidad es que el usuario pueda ver los totales y la cantidad de pesadas de dichas básculas segun 3 grupos de formar combinaciones?
Es decir algo como:
"Quiero que en mi primer consulta, me muestra a las básculas 1 y 2; en mi segunda consulta la 3 y 4; y en la tercera a la 5 y 6"
O algo como:
"En mi primer agrupamiento, a 1 y 4. En el segundo grupo a 4 y 2. En el tercero, a 5 y 6."

Si es esto último que estoy pensando me parece que si es válido entonces la forma de la consulta; aunque se la puede refinar un poco: la parte WHERE puede ser así:



sql
  1. WHERE Bascula IN (xx,yy,...,zz)



Saludos,
  • 0

#4 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 23 diciembre 2008 - 11:00

Hola,

Mientras Dephius ve la parte de los Queries, yo te ayudo a reducir lineas :D



delphi
  1. //Leemos el ultimo estado de los checkbox el cual se guardo en un INI
  2. procedure TdmDatos.LeerGrupos;
  3. var
  4.   i: integer;
  5.   F: TiniFile;
  6. begin
  7.   F := TIniFile.Create(ExtractFilePath(Paramstr(0)) + Archivo);
  8.   for i := 1 to 6 do begin
  9.       Grupo1[i] := F.readbool('Grupo'+inttostr(i), 'Bascula'+inttostr(i), False);
  10.   end;
  11.   for i := 1 to 6 do begin
  12.       Grupo2[i] := F.readbool('Grupo'+inttostr(i), 'Bascula'+inttostr(i), False);
  13.   end;
  14.   for i := 1 to 6 do begin
  15.       Grupo3[i] := F.readbool('Grupo'+inttostr(i), 'Bascula'+inttostr(i), False);
  16.   end;
  17. end;



Por otro lado, no seria mejor que en el archivo INI tengas directamente los valores 0 y 1 en lugar de False y True?

Con eso te ahorras todo este código.........



delphi
  1. {Segun el estado de cada elemento del array (TRUE / FALSE)
  2.   asignamos un numero a los indices}
  3. procedure TdmDatos.AsignaBasculaGrupo1;
  4. begin
  5.   if Grupo1[1] then
  6.     idx11 := 1
  7.   else
  8.     idx11 := 0;
  9.  
  10.   if Grupo1[2] then
  11.     idx12 := 2
  12.   else
  13.     idx12 := 0;
  14.  
  15.   if Grupo1[3] then
  16.     idx13 := 3
  17.   else
  18.     idx13 := 0;
  19.  
  20.   if Grupo1[4] then
  21.     idx14 := 4
  22.   else
  23.     idx14 := 0;
  24.  
  25.   if Grupo1[5] then
  26.     idx15 := 5
  27.   else
  28.     idx15 := 0;
  29.  
  30.   if Grupo1[6] then
  31.     idx16 := 6
  32.   else
  33.     idx16 := 0;
  34. end;
  35.  
  36. {Segun el estado de cada elemento del array (TRUE / FALSE)
  37.  asignamos un numero a los indices}
  38. procedure TdmDatos.AsignaBasculaGrupo2;
  39. begin
  40.   if Grupo2[1] then
  41.     idx21 := 1
  42.   else
  43.     idx21 := 0;
  44.  
  45.   if Grupo2[2] then
  46.     idx22 := 2
  47.   else
  48.     idx22 := 0;
  49.  
  50.   if Grupo2[3] then
  51.     idx23 := 3
  52.   else
  53.     idx23 := 0;
  54.  
  55.   if Grupo2[4] then
  56.     idx24 := 4
  57.   else
  58.     idx24 := 0;
  59.  
  60.   if Grupo2[5] then
  61.     idx25 := 5
  62.   else
  63.     idx25 := 0;
  64.  
  65.   if Grupo2[6] then
  66.     idx26 := 6
  67.   else
  68.     idx26 := 0;
  69. end;
  70.  
  71. {Segun el estado de cada elemento del array (TRUE / FALSE)
  72.  asignamos un numero a los indices}
  73. procedure TdmDatos.AsignaBasculaGrupo3;
  74. begin
  75.   if Grupo3[1] then
  76.     idx31 := 1
  77.   else
  78.     idx31 := 0;
  79.  
  80.   if Grupo3[2] then
  81.     idx32 := 2
  82.   else
  83.     idx32 := 0;
  84.  
  85.   if Grupo3[3] then
  86.     idx33 := 3
  87.   else
  88.     idx33 := 0;
  89.  
  90.   if Grupo3[4] then
  91.     idx34 := 4
  92.   else
  93.     idx34 := 0;
  94.  
  95.   if Grupo3[5] then
  96.     idx35 := 5
  97.   else
  98.     idx35 := 0;
  99.  
  100.   if Grupo3[6] then
  101.     idx36 := 6
  102.   else
  103.     idx36 := 0;
  104. end;



Y en tus parámetros solo harias esto



delphi
  1.       Params.ParamByName('Bas1').Value := Grupo1[1];
  2.       Params.ParamByName('Bas2').Value := Grupo1[2];
  3.       Params.ParamByName('Bas3').Value := Grupo1[3];
  4.       Params.ParamByName('Bas4').Value := Grupo1[4];
  5.       Params.ParamByName('Bas5').Value := Grupo1[5];
  6.       Params.ParamByName('Bas6').Value := Grupo1[6];



Salud OS

  • 0

#5 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 24 diciembre 2008 - 09:54

Bueno, no pude sacar tiempo, y en unas horas me estoy llendo. Brevemente te comento que yo lo haría así:



delphi
  1. const
  2.   CANT_GRUPOS = 3;
  3.   CANT_BASCULAS = 6;
  4.  
  5. type
  6.   TMatrizBasculas[1..CANT_GRUPOS,1..CANT_BASCULAS] of boolean; //matriz de lectura de archivos
  7.  
  8. Y luego al leer el ini, algo como esto:
  9.  
  10. var Matriz: TMatrizBasculas;
  11.     i,j: integer;
  12.  
  13. for i := 1 TO CANT_GRUPOS do
  14.   for j := 1 to CANT_BASCULAS do
  15.     Matriz[i,j] := F.Readbool('Grupo' + IntToStr(i), 'Bascula' + IntToStr(j), False);



Te olvidas de los idx. Ya con esa matriz se hace todo el trabajo.

Tu consulta SQL se puede incluso resumir en una sola:



sql
  1. SELECT COUNT(*) AS Pesadas, SUM(peso) AS Total
  2. FROM Datos
  3. WHERE Bascula IN (xx1,yy1,..,zz1)
  4. UNION
  5. SELECT COUNT(*) AS Pesadas, SUM(peso) AS Total
  6. FROM Datos
  7. WHERE Bascula IN (xx2,yy2,..,zz2)
  8. UNION
  9. SELECT COUNT(*) AS Pesadas, SUM(peso) AS Total
  10. FROM Datos
  11. WHERE Bascula IN (xx3,yy3,..,zz3)



Siendo xx,yy,..zz los valores idx que tu confeccionas. Para distinguir un grupo de otro, le asocie un número.
En lo posible debería evitarse esos UNIONs, tienden a ser un poco lentos. Pero es que como en realidad la consulta es la misma y lo único que cambia es la parte where... me parece cómodo; y en vez de hacer count(*) sería oportuno hacer count(nombre_campo). El * obliga al motor evaluar sobre las tablas de sistemas para saber cuantos campos son, luego hace unas operaciones para extraer los campos y al final termina haciendo esto:
count(campo1, campo2, ..., campoN)

Ahora la rutina que transforma los valores de la matriz en idx lo que hace es simplemente formar la cadena de la parte IN de la consulta:



delphi
  1. var texto_in: string;
  2. begin
  3.   // por ejemplo si quieres para el grupo 1
  4.   texto_in := '(';
  5.   for j := 1 to CANT_BASCULAS do
  6.     begin
  7.         if Matriz[1,j]
  8.           then begin
  9.                   if j = CANT_BASCULAS
  10.                     then texto_in := texto_in + IntToStr(j)
  11.                     else texto_in := texto_in  + IntToStr(j) + ' ,';
  12.                 end;
  13.     end;
  14.   texto_in := texto_in + ')';
  15. end;



Al final de esa rutina tendrás una cadena del tipo (xx,yy,..zz) con los valores de las básculas a evaluar. Sólo resta añadir esa cadena al SQL definitivo.

Creo que con el aporte de Egostar y el mio ya tienes para trabajar.

Espero que se entienda.
  • 0

#6 FGarcia

FGarcia

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 687 mensajes
  • LocationMéxico

Escrito 24 diciembre 2008 - 08:42

Delphius, Egostar Gracias por la atencion y ayuda.

Aclarando dudas:

1. Solo son seis (6) básculas.  Puedo agrupar en tres grupos o a lo mejor solo en dos (1,2,3) (4,5,6) o en cualquier combinacion que no repita una bascula en otro grupo.

2. La funcion de leer el ini quedo asi:



delphi
  1. //Leemos el ultimo estado de los checkbox el cual se guardo en un INI
  2. procedure TdmDatos.LeerGrupos;
  3. var
  4.   i,j: integer;
  5.   F: TiniFile;
  6. begin
  7.  
  8.   F := TIniFile.Create(ExtractFilePath(Paramstr(0)) + Archivo);
  9.  
  10.   for i := 1 TO CANT_GRUPOS do
  11.     for j := 1 to CANT_BASCULAS do
  12.       GrupoBascula[i,j] := F.Readbool('Grupo ' + IntToStr(i),'Bascula ' + IntToStr(j),False);
  13. end;



Con lo cual me resulta una matriz con un contenido asi (por ejemplo):

GrupoBascula[1,1] = True
GrupoBascula[1,2] = True
GrupoBascula[1,3] = False
GrupoBascula[1,4] = False
GrupoBascula[1,5] = False
GrupoBascula[1,6] = False
.
.
.
GrupoBascula[3,4] = False
GrupoBascula[3,5] = True
GrupoBascula[3,6] = True



Aun me queda asignar a los indices (idx) el numero de bascula que es TRUE para armar la consulta. En eso estoy.

Egostar en el ini se guardan solo valores 0 y 1 correspondiente a los estados False y True de los checkbox. A los idx les asigno un numero de báscula (1..6) si el estado del checkbox es TRUE; si es FALSE les asigno el valor 0.  A lo mejor no entendi bien lo que me sugeriste.

Vamos a continuar. Nuevamente les repito mi agradecimiento por su ayuda.
  • 0

#7 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 25 diciembre 2008 - 09:18

Hola,

Me imagino que en algun lugar estas guardando esos valores de True y False, bueno en lugar de hacer eso cuando debas guardar true, guarda el numero de bascula y cuan sea False guarda 0, de tal forma que cuando recuperas los valores desde el INI te quedarias así:

Usando tu mismo ejemplo:



delphi
  1. GrupoBascula[1,1] = 1
  2. GrupoBascula[1,2] = 2
  3. GrupoBascula[1,3] = 0
  4. GrupoBascula[1,4] = 0
  5. GrupoBascula[1,5] = 0
  6. GrupoBascula[1,6] = 0
  7. .
  8. .
  9. .
  10. GrupoBascula[3,4] = 0
  11. GrupoBascula[3,5] = 5
  12. GrupoBascula[3,6] = 6



Es obvio que TGroup ya no seria Bool sino de tipo Integer, ademas de que debes de cambiar la funcion F.Readbool por F.ReadInteger....

Salud OS
  • 0

#8 FGarcia

FGarcia

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 687 mensajes
  • LocationMéxico

Escrito 25 diciembre 2008 - 10:26

Obtengo puntos por Km de codigo?  :D  :p

Bueno asi esta la unit modificada (Gracias a Al González por su ayuda y tiempo):



delphi
  1. unit UdmDatos;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils, Classes, DB, IBCustomDataSet, IBQuery, IniFiles, StrUtils, GHFMath;
  7.  
  8. const
  9.   CANT_GRUPOS = 3;
  10.   CANT_BASCULAS = 6;
  11.  
  12. type
  13.   TMatrizBasculas = array[1..CANT_GRUPOS,1..CANT_BASCULAS] of integer; //matriz de lectura de numero de bascula
  14.  
  15. type
  16.   TMatrizEstado = array[1..CANT_GRUPOS,1..CANT_BASCULAS] of boolean; //matriz de lectura de estado de checkbox por cada bascula
  17.  
  18. type
  19.   TdmDatos = class(TDataModule)
  20.     qySumaGrupos: TIBQuery;
  21.     procedure DataModuleCreate(Sender: TObject);
  22.   private
  23.     { Private declarations }
  24.     procedure LeerGrupos;
  25.     procedure OrganizaGrupos;
  26.   public
  27.     { Public declarations }
  28.     GrupoBascula: TMatrizBasculas;
  29.     EstadoBasculas: TMatrizEstado;
  30.     Cuantos1,Cuantos2,Cuantos3: integer;
  31.     Total1,Total2,Total3: double;
  32.     txtGrupo1,txtGrupo2,txtGrupo3: string;
  33.     procedure SumarGrupos;
  34.   end;
  35.  
  36. const
  37.   Archivo = 'Configura.ini';
  38.  
  39. var
  40.   dmDatos: TdmDatos;
  41.  
  42. implementation
  43.  
  44. uses
  45.   UdmCnx;
  46.  
  47. {$R *.dfm}
  48.  
  49. { TdmDatos }
  50.  
  51. //Al crear el modulo se ejecutan estos procedimientos
  52. procedure TdmDatos.DataModuleCreate(Sender: TObject);
  53. begin
  54.   LeerGrupos;
  55.   OrganizaGrupos;
  56.   SumarGrupos;
  57. end;
  58.  
  59. //Leemos el ultimo estado de los checkbox el cual se guardo en un INI
  60. procedure TdmDatos.LeerGrupos;
  61. var
  62.   i,j: integer;
  63.   F: TiniFile;
  64. begin
  65.  
  66.   F := TIniFile.Create(ExtractFilePath(Paramstr(0)) + Archivo);
  67.  
  68.   for i := 1 TO CANT_GRUPOS do
  69.     for j := 1 to CANT_BASCULAS do
  70.       GrupoBascula[i,j] := F.ReadInteger('Grupo ' + IntToStr(i),'Bascula ' + IntToStr(j),0);
  71.  
  72.   for i := 1 TO CANT_GRUPOS do
  73.     for j := 1 to CANT_BASCULAS do
  74.       EstadoBasculas[i,j] := F.ReadBool('Grupo ' + IntToStr(i),'Bascula ' + IntToStr(j),False);
  75. end;
  76.  
  77.  
  78. {Creamos las cadenas que definen el numero-estado de las basculas}
  79. procedure TdmDatos.OrganizaGrupos;
  80.   //***********Funcion auxiliar del procedimiento
  81.   //**Basada en un codigo de Seoane
  82.   //**http://www.clubdelphi.com/foros/showthread.php?t=45612
  83.   function QuitaComa(Str: String): String;
  84.   var
  85.     tmpStr: string;
  86.   begin
  87.     tmpStr := Str; //(x,y,z,)
  88.     tmpStr := RightStr(tmpStr,2); //,)
  89.     if (pos(',',tmpStr) > 0) then
  90.       delete(Str,(length(Str)-1),1); //Delete(Str,Start,Count)
  91.     Result:= Str //(x,y,z)
  92.   end;
  93.   //***********************************************
  94.  
  95. var
  96.   j: integer;
  97. begin
  98.   // Armamos la cadena del grupo 1
  99.   txtGrupo1 := '(';
  100.   for j := 1 to CANT_BASCULAS do
  101.     begin
  102.       if EstadoBasculas[1,j] then //Cuales Checkbox estan marcados (TRUE)
  103.         begin
  104.           if j = CANT_BASCULAS then
  105.             txtGrupo1 := txtGrupo1 + IntToStr(GrupoBascula[1,j]) //Numero de bascula correspondiente
  106.           else
  107.             txtgrupo1 := txtgrupo1  + IntToStr(GrupoBascula[1,j]) + ' ,';
  108.         end
  109.       else
  110.         txtgrupo1 := txtgrupo1  + IntToStr(0) + ' ,';
  111.     end;
  112.   txtGrupo1 := txtGrupo1 + ')'; //Si no esta en TRUE la bascula 6 en True se genera (x,y[b],[/b])
  113.   txtGrupo1 := QuitaComa(txtGrupo1); //Eliminamos la coma final
  114.  
  115.   //Armamos la cadena del grupo 2
  116.   txtGrupo2 := '(';
  117.   for j := 1 to CANT_BASCULAS do
  118.     begin
  119.       if EstadoBasculas[2,j] then  //Si el estado es TRUE
  120.         begin
  121.           if j = CANT_BASCULAS then
  122.             txtGrupo2 := txtGrupo2 + IntToStr(GrupoBascula[2,j])
  123.           else
  124.             txtgrupo2 := txtgrupo2  + IntToStr(GrupoBascula[2,j]) + ' ,';
  125.         end
  126.       else
  127.         txtgrupo2 := txtgrupo2  + IntToStr(0) + ' ,';
  128.     end;
  129.   txtGrupo2 := txtGrupo2 + ')';
  130.   txtGrupo2 := QuitaComa(txtGrupo2);
  131.  
  132.   //Armamos la cadena del Grupo3
  133.   txtGrupo3 := '(';
  134.   for j := 1 to CANT_BASCULAS do
  135.     begin
  136.       if EstadoBasculas[3,j] then  //Si el estado es TRUE
  137.         begin
  138.           if j = CANT_BASCULAS then
  139.             txtGrupo3 := txtGrupo3 + IntToStr(GrupoBascula[3,j])
  140.           else
  141.             txtgrupo3 := txtgrupo3  + IntToStr(GrupoBascula[3,j]) + ' ,';
  142.         end
  143.       else
  144.         txtgrupo3 := txtgrupo3  + IntToStr(0) + ' ,';
  145.     end;
  146.   txtGrupo3 := txtGrupo3 + ')';
  147.   txtGrupo3 := QuitaComa(txtGrupo3);
  148. end;
  149.  
  150. {Ejecutamos la consulta en tres pasos. Al intentar hacerlo en un paso (UNION) se genera un error extraño en el StringGrid,
  151.   la fila 1 se pone siempre en 0 si algun grupo no tiene ninguna seleccion (todo en 0)}
  152. procedure TdmDatos.SumarGrupos;
  153. begin
  154.   //********************GRUPO 1*****************************************
  155.   with qySumaGrupos do
  156.     begin
  157.       close;
  158.       sql.Clear ;
  159.       sql.Add('SELECT count(*) AS Pesadas, ' +
  160.               'sum(peso) AS Total ' +
  161.               'FROM Datos WHERE Bascula IN ' + txtGrupo1);    //(1,2,0,0,0,0)
  162.       open;
  163.     end;
  164.   if not qySumaGrupos.IsEmpty then
  165.     begin
  166.       //ghInt y ghFloat forman parte de ghMath de la biblioteca GHFreebrary de AL González devuelven un 0 si existiese un NULL
  167.       Cuantos1 := ghInt(qySumaGrupos['Pesadas']); //FieldValues es la propiedad Default del dataset
  168.       Total1 := ghFloat(qySumaGrupos['Total']);  //Se accede a ella de forma implicita con la sintaxis Dataset[Campo]
  169.     end;
  170.  
  171.  
  172.   //************************GRUPO 2**********************************
  173.   with qySumaGrupos do
  174.     begin
  175.       close;
  176.       sql.Clear ;
  177.       sql.Add('SELECT count(*) AS Pesadas, ' +
  178.               'sum(peso) AS Total ' +
  179.               'FROM Datos WHERE Bascula IN ' + txtGrupo2);    //(0,0,3,4,0,0)
  180.       open;
  181.     end;
  182.   if not qySumaGrupos.IsEmpty then
  183.     begin
  184.       Cuantos2 := ghInt(qySumaGrupos['Pesadas']); //FieldValues es la propiedad Default del dataset
  185.       Total2 := ghFloat(qySumaGrupos['Total']);  //Se accede a ella de forma implicita con la sintaxis Dataset[Campo]
  186.     end;
  187.  
  188.  
  189.   //*******************GRUPO 3 ***************************************
  190.   with qySumaGrupos do
  191.     begin
  192.       close;
  193.       sql.Clear ;
  194.       sql.Add('SELECT count(*) AS Pesadas, ' +
  195.               'sum(peso) AS Total ' +
  196.               'FROM Datos WHERE Bascula IN ' + txtGrupo3);    //(0,0,0,0,5,6)
  197.       open;
  198.     end;
  199.   if not qySumaGrupos.IsEmpty then
  200.     begin
  201.       Cuantos3 := ghInt(qySumaGrupos['Pesadas']); //FieldValues es la propiedad Default del dataset
  202.       Total3 := ghFloat(qySumaGrupos['Total']);  //Se accede a ella de forma implicita con la sintaxis Dataset[Campo]
  203.     end;
  204.  
  205. end;
  206.  
  207.  
  208.  
  209. end.



Definitivamente el codigo se redujo bastante. Seria fabuloso reducir aun mas la consulta.  :D

El codigo de la consulta en un paso y que genera errores extraños (tal vez alguien vea el error que no veo -¿sera efecto de navidad? - ) :



delphi
  1. procedure TdmDatos.SumarGrupos;
  2. begin
  3.   with qySumaGrupos do
  4.     begin
  5.       close;
  6.       sql.Clear ;
  7.       sql.Add('SELECT count(*) AS Pesadas, ' +
  8.               'sum(peso) AS Total ' +
  9.               'FROM Datos WHERE Bascula IN ' + txtGrupo1 +  //(1,2)
  10.               ' UNION ' +
  11.                 'SELECT count(*),' +
  12.                 'sum(peso) ' +
  13.                 'FROM Datos WHERE Bascula IN ' + txtGrupo2 +  //(3,4)
  14.               ' UNION ' +
  15.                 'SELECT count(*),' +
  16.                 'sum(peso) ' +
  17.                 'FROM Datos WHERE Bascula IN ' + txtGrupo3);  //(5,6)
  18.       open;
  19.     end;
  20.  
  21.   if not qySumaGrupos.IsEmpty then
  22.     begin
  23.       Cuantos1 := ghInt(qySumaGrupos['Pesadas']); //FieldValues es la propiedad Default del dataset
  24.       Total1 := ghFloat(qySumaGrupos['Total']);  //Se accede a ella de forma implicita con la sintaxis Dataset[Campo]
  25.  
  26.       qySumaGrupos.Next; //Delphi ve el resultado como una tabla con
  27.                         //tres registros. Hay que navegar (Next)
  28.  
  29.       Cuantos2 := ghInt(qySumaGrupos['Pesadas']);
  30.       Total2 := ghFloat(qySumaGrupos['Total']);
  31.  
  32.       qySumaGrupos.Next;
  33.  
  34.       Cuantos3 := ghInt(qySumaGrupos['Pesadas']);
  35.       Total3 := ghFloat(qySumaGrupos['Total']);
  36.     end;
  37. end;



Gracias nuevamente por su ayuda y el tiempo .
  • 0

#9 FGarcia

FGarcia

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 687 mensajes
  • LocationMéxico

Escrito 25 diciembre 2008 - 10:49

Solamente por si alguien quiere revisarlo anexo el codigo y la BD que estoy usando. Solo descomprimir ambos en una misma carpeta. firebird 2.0 y delphi 7. El unico componente externo es la GHFreebrary. Grupos es el codigo y DatosCap es la BD.

Archivos adjuntos


  • 0

#10 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 26 diciembre 2008 - 05:20

Hola FGarcía,
Veo que se avanzó en el tema.
Lo que yo he notado cuando ejecuté dicha consulta (IBExpert) en mi Firebird 1.5 es que los registros me los devuelve en el orden inverso. Es decir algo así:
datos grupo 3
datos grupo 2
datos grupo 1

Pero funciona. Devuelve los datos correctos, pero no ordenados. Tal vez se debió a que usé un indice descendiente... no se... tendría que ver. La prueba la hice apresurado y con una de las tablas de la DB de ejemplo. Admito que no me fijé en los índices. Disculpa.

Con respecto al tema de formar la cadena de la parte IN yo veo que se puede resumir en una sola:



delphi
  1. function GetTextoIn(NroGrupo: integer): string;
  2. var j: integer;
  3. begin
  4.   result := '(';
  5.   for j := 1 to CANT_BASCULAS do
  6.     if EstadoBasculas[NroGrupo,j] // es true el valor leído desde archivo
  7.         then result := result + IntToStr(j) + ' ,';
  8.   result := QuitarComa(result) + ')';
  9. end;



Tu repites la rutina 3 veces, una por grupo.

Me resulta extraño que tengas otra matriz con valores enteros ¿Para qué? No termino de comprender.

Yo llego a la conclusión de que si tenemos el estado en TRUE y el índice (el j) en la matriz podemos indentificar únivocamente a la báscula y por tanto confirmar que la báscula j-ésima ha sido seleccionada.
Si existe una fiel correspondencia entre el "ID" de la báscula y el índice en la matriz, entonces nos podemos evitar una segunda matriz.

Ahora, una pregunta ¿y si no selecciona ninguna? ¿Que hacemos?
1. no filtrar y considerar a todas las básculas. (Sin WHERE)
2. dar una advertencia y pedir que filtre al menos una.

Esa función GetTextoIn debería funcionar siempre y cuando exista al menos una selección. Noté que en tu código le introduces el cero. ¿Porqué? ¿Tiene algún significado en especial? En mi código debería haber una salida del tipo "()".
Eso es ya una cuestión de "detalle".

Después le hecho una miradita a tu código.
Saludos,
  • 0

#11 FGarcia

FGarcia

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 687 mensajes
  • LocationMéxico

Escrito 26 diciembre 2008 - 06:10

Con respecto a lo de que devuelve los resultados en orden inverso, si, si lo hace, de hecho no se a que se debe y hasta este momento que me dices que asi te resulto confirmo la respuesta.

Si la salida es () y se genera un error de SQL que desconoce la expresion (. Por eso cambie para que llene las cadenas (1,2,0,0,0,0) si no seleccionas ninguna pues devuelve solo (0,0,0,0,0,0) y no genera error.

Gracias por tu tiempo.
  • 0

#12 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 26 diciembre 2008 - 06:29

Hola FGarcia,
¿Entonces no era algo que me sucedía a mi lo de los regitros inversos? Bueno... no se... tal vez si pruebo poniendo la SQL alrreves... digo algo como:



sql
  1. SELECT ...
  2. WHERE IN (xx3,yy3,...,zz3)
  3. UNION
  4. SELECT ...
  5. WHERE IN (xx2,yy2,...,zz2)
  6. UNION
  7. SELECT ...
  8. WHERE IN (xx1,yy1,...,zz1)


No tengo Firebird abierto en este momento.

Gracias por aclararme lo de los ceros.
Ummm, yo mas bien lo programaría para que antes de lanzar la SQL chequear si el texto es () y en caso afirmativo lanzar una SQL sin where.

No se si es mucho lío lanzar tres consultas simples, como tu haces... o directamente una sola con los unions. Lo que si es bueno es emplear un solo TQuery. No veo, al menos asi opino yo, tener tres TQuerys para lanzar tres consultas que son "las mismas"... bastaría con lanzar, guardar en el stringGrid, cerrar y volver a lanzarla con los nuevos datos en en IN.

Saludos,
  • 0

#13 FGarcia

FGarcia

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 687 mensajes
  • LocationMéxico

Escrito 27 diciembre 2008 - 04:22

OK, ya esta eliminada la segunda matriz. No me preguntes porque la ponia pues no le encontre ya logica.  :$

Con respecto a lo de las queries eso ya lo habia dejado en una sola, solo la lanzo tres veces. No he vuelto a probar con lo de la UNION.



delphi
  1. procedure TdmDatos.SumarGrupos;
  2.  
  3.   //***********Funcion auxiliar del procedimiento ***************************
  4.   //**Basada en un codigo de Seoane
  5.   //**http://www.clubdelphi.com/foros/showthread.php?t=45612
  6.   function QuitarComa(Str: String): String;
  7.   var
  8.     tmpStr: string;
  9.   begin
  10.     tmpStr := Str; //(x,y,z,)
  11.     tmpStr := RightStr(tmpStr,1); //,
  12.     if (pos(',',tmpStr) > 0) then
  13.       delete(Str,(length(Str)),1); //Delete(Str,Start,Count)
  14.     Result:= Str //(x,y,z)
  15.   end;
  16.   //*************************************************************************
  17.  
  18.   function GetTextoIn(NroGrupo: integer): string;
  19.   var
  20.     j: integer;
  21.   begin
  22.     result := '(';
  23.  
  24.     for j := 1 to CANT_BASCULAS do
  25.       if EstadoBasculas[NroGrupo,j] then // es true el valor leído desde archivo
  26.         result := result + IntToStr(j) + ' ,'
  27.       else
  28.         result := result + IntToStr(0) + ' ,';
  29.  
  30.     result := QuitarComa(result) + ')';
  31.   end;
  32.   //*************************************************************************
  33.  
  34. begin
  35.  
  36.   //********************GRUPO 1**********************************************
  37.   with [b]qySumaGrupos[/b] do
  38.     begin
  39.       close;
  40.       sql.Clear ;
  41.       sql.Add('SELECT count(*) AS Pesadas, ' +
  42.               'sum(peso) AS Total ' +
  43.               'FROM Datos WHERE Bascula IN ' + GetTextoIn(1));    //(1,2)
  44.       open;
  45.     end;
  46.   if not qySumaGrupos.IsEmpty then
  47.     begin
  48.       Cuantos1 := ghInt(qySumaGrupos['Pesadas']); //FieldValues es la propiedad Default del dataset
  49.       Total1 := ghFloat(qySumaGrupos['Total']);  //Se accede a ella de forma implicita con la sintaxis Dataset[Campo]
  50.     end;
  51.  
  52. /+++++Se repite para las otras dos solo cambio el parametro de GetTextoIn(X)


  • 0




IP.Board spam blocked by CleanTalk.