Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   SQL (https://www.clubdelphi.com/foros/forumdisplay.php?f=6)
-   -   Seleccion multiple para montar query (https://www.clubdelphi.com/foros/showthread.php?t=67543)

tgsistemas 22-04-2010 09:45:45

Seleccion multiple para montar query
 
Hola a tod@s,

estoy atascado dándole vueltas a este tema pero no tengo nada claro como solventarlo y que sea ágil, por lo que os pido ayuda nuevamente sobre ideas o procesos que se os ocurran....

En un grid (asociado a un ClientDataSet) tengo un campo temporal "seleccionado" para que el usuario escoja la tienda (1.200 registros) sobre los que lanzar una segunda qry que realiza cálculos, hasta aquí todo bien. El problema lo tengo a la hora de cómo montar el segundo qry en función de las tiendas que se hayan seleccionado.

Hasta ahora estaba pensando en recorrer el cdsTDAS y en función del campo "seleccionado" (boolean) ir guardando el codigo de la tienda para luego montar la qry con las tiendas seleccionadas, algo así :
Código Delphi [-]
procedure TFDlgSlccionMltple.BtnOkClick(Sender: TObject);
var
  Marca : TBookmark;
begin
  isqlselmult := '';
  with cdsTDAS do
  begin
    DisableControls;
    Marca := GetBookMark;
    try
      First;
      while not cdsTDAS.EOF do begin
        if FieldByName('tmp_select').AsBoolean then
        begin
          if (isqlselmult = EmptyStr) then
          begin
            isqlselmult := 'com = ' + cdsTDAS.fieldbyname('com').AsString + ' ';
          end else begin
            isqlselmult := isqlselmult + 'com = ' + cdsTDAS.fieldbyname('com').AsString + ', or ';
          end;
        end;
        Next;
      end;
    finally
      GoToBookmark(Marca);
      FreeBookmark(Marca);
      EnableControls;
    end;
  end;
end;

pero aquí tengo algunas dudas,
1.- se podría montar un query como el siguiente o habría limitaciones ?? :
Código SQL [-]
select campo1, campo2, campo3 from tbPrtesDia where (cdgotda = XXXX, or cdgotda= XXX1, or cdgotda=XXAX,..... )//etc, etc.... pueden ser 1200 cdgo!!!

2.- cómo puedo eliminar el último "', or '" de la qry que voy montando??


3.- no me parece la mejor consulta del mundo :( pero no se me ocurre o conozco otra forma de optimizarla.

no se si me he explicado correctamente, agradecería vuestra ayuda, se admiten propuestas :D:D

Saludos y Gracias

tgsistemas 22-04-2010 12:21:48

el código de arriba está mal, sorry por no depurarlo, el que funciona correctamente es :

Código Delphi [-]
procedure TFDlgSlccionMltple.BtnOkClick(Sender: TObject);
var
  Marca : TBookmark;
begin
  isqlselmult := '';
  with cdsTDAS do
  begin
    DisableControls;
    Marca := GetBookMark;
    try
      First;
      while not cdsTDAS.EOF do begin
        if FieldByName('tmp_select').AsBoolean then
        begin
          if (isqlselmult = EmptyStr) then
          begin
            isqlselmult := 'centro = ' + cdsTDAS.fieldbyname('com').AsString;
          end else begin
            isqlselmult := isqlselmult + ' or centro = ' + cdsTDAS.fieldbyname('com').AsString;
          end;
        end;
        Next;
      end;
    finally
      GoToBookmark(Marca);
      FreeBookmark(Marca);
      EnableControls;
    end;
  end;
end;

lanza la consulta correctamente y no tarda mucho la verdad es que me ha sorprendido....

las dudas 1 y 2 ya están resueltas :D pero sigo teniendo la duda de si consideráis que es la mejor forma de hacerlo.

gracias y saludos

duilioisola 22-04-2010 13:12:18

Opcion 1:

Si el campo tmp_select no es temporal (está en la tabla), podrías hacer algo asi:

- Marcas la tabla de selección
- Luego haces este select:
Código SQL [-]
select campo1, campo2, campo3 from tbPrtesDia 
where (cdgotda in (select tienda from tabla_seleccion where tmp_select=1))

En principio no tiene límite de cuantas tiendas están seleccionadas

Opcion 2:

También puedes generar el sql, de una forma parecida a la que ya haces:
Código SQL [-]
select campo1, campo2, campo3 from tbPrtesDia 
where (cdgotda in (XXX1,XXX2,XXX3,XXX4,...))

Deberás probar los límites de la base de datos que utilices.
No se si te permitirá hacer un sql muy largo o si te permitirá tantos "or" , si seleccionas todas las tiendas.

fjcg02 22-04-2010 13:52:01

Te sugiero un pequeño cambio que puede que te facilite las cosas.
Incluye una opción para que lo que tú selecciones lo incluya o excluya. Claro, la generación de la select será diferente en cada caso.

Pienso que un usuario que tenga que seleccionar de esa lista, una de dos. O selecciona todas o sólamente un grupo. De esta manera seguramente la select te saldrá más corta. Aunque ya te digo, que el usuario seleccione entre 1200 registros, puede ser un infierno. Concretamente yo, si una lista tiene más de 30 registros, soy incapaz de hacer nada con ella.

Un saludo

tgsistemas 22-04-2010 16:45:02

gracias duilioisola y [fjcg02] por las respuestas,

lamentablemente el campo "seleccionado" es un temporal en el ClientDataSet.

El proceso es el siguiente :
1.- tienen una ventana de selección con 3 dbgrid dónde se agrupan esos registros en función de la zona de venta, director de venta y tienda. Pero no puedo utilizar esas agrupaciones de zona de venta o director de venta ya que en la tabla de partes no se conserva esa relación.
2.- la selección de las tiendas puede ser en función de varios criterios, o bien por los agrupamientos del punto 1 o bien seleccionándolas de forma aleatoria manualmente por lo que no me queda otra que recorrer la tabla de tiendas para saber cuáles han seleccionado.

duilioisola, respecto a esa qry, no se me había ocurrido pasarle todos valores en una sola validación como indicas, eso debo probarlo :confused:
hasta ahora está funcionando con la qry que dije al principio (la de tantos "or ...").

sigo probando y os cuento, pero si veis algo que se pueda mejorar no dudéis en decirlo ;)

Saludos

eflosten 22-04-2010 16:54:03

Si quieres seguir con los OR yo tuve un problema parecido hace poco, lo solucioné usando una cadena, que era la condición autogenerada, e incrustandola en el SQL.

Código Delphi [-]
if Cadena='' then Cadena:='Campo='+valor;
else cadena:=Cadena+' or Campo='+valor;
DataSet.SQL:='SELECT FROM (todo lo que vaya aqui) WHERE '+Cadena;

Y con respecto a la multiselección, por qué no haces un Array dinámico en el evento que sea necesario (OnSelectRow quizá? no tengo el delphi delante para mirar xD) con los registros que selecciones, luego es solo hacer un bucle for.

tgsistemas 22-04-2010 18:03:09

gracias eflosten por la respuesta,

muestro el proceso completo para que se entienda mejor, un código vale más que mil palabras, sobre todo si son mías ;)

este es el resultado de una form modal dónde se hace la selección de las tiendas :
Código Delphi [-]
procedure TFDlgSlccionMltple.BtnOkClick(Sender: TObject);
var
  Marca : TBookmark;
begin
  isqlselmult := ''; //variable pública dónde guardo los datos del where
  with cdsTDAS do
  begin
    DisableControls;
    Marca := GetBookMark;
    try
      First;
      while not cdsTDAS.EOF do begin
        if FieldByName('tmp_select').AsBoolean then
        begin
          if (isqlselmult = EmptyStr) then
          begin
            isqlselmult := 'centro = ' + cdsTDAS.fieldbyname('com').AsString;
          end else begin
            isqlselmult := isqlselmult + ' or centro = ' + cdsTDAS.fieldbyname('com').AsString;
          end;
        end;
        Next;
      end;
    finally
      GoToBookmark(Marca);
      FreeBookmark(Marca);
      EnableControls;
    end;
  end;
end;

esta es la llamada a mostrar la form modal de selección de las tiendas y la cadena completa del qry con los where :
Código Delphi [-]
procedure TFInfrmes_SupSelect.btn5Click(Sender: TObject);
begin
  with TFDlgSlccionMltple.Create(self) do begin
    try
      if ShowModal = mrok then
      begin
        {consulta DETALLE ACUMULADOS}
        isqldetsel := 'SELECT centro, max(fecha) as fecha, cdgodiet, sec_to_time(SUM(time_to_sec(hllmndo))) AS rhllmndo, ' +
              'SUM(visitas) AS rvisitas, SUM(motnotot) AS rmotnotot, SUM(visitas) + SUM(motnotot) AS rcntctos, ' +
              'SUM(motno01) AS rmotnotot01, SUM(motno02) AS rmotnotot02, SUM(motno03) AS rmotnotot03, SUM(motno04) AS rmotnotot04, ' +
              'SUM(motno05) AS rmotnotot05, SUM(motno06) AS rmotnotot06, SUM(motno07) AS rmotnotot07,  SUM(motno08) AS rmotnotot08, ' +
              'SUM(motno09) AS rmotnotot09,  SUM(motnoes02) AS rmotnototes01, SUM(motnoes02) AS rmotnototes02, ' +
              'SUM(segllam) AS rsegllam, SUM(vllamdec) AS rvllamdec, SUM(llamtot) AS rllamtot, SUM(impventas) AS rimpventas ' +
              'FROM tb03P WHERE ((fecha between :fdesde and :fhasta) AND (' + isqlselmult +'))' +
              'GROUP BY tb03P.centro ' +
              'order by tb03P.centro, tb03P.fecha desc;';
      end;
    finally
      Free;
    end;
  end;
end;

lanzo el qry de cálculos :
Código Delphi [-]
//en otro evento se lanza .....
  with zroqryinfrme_sup do
  begin
    Close;
    sql.Clear;
    SQL.Add(isqldetsel);  //esta es la consulta montada manualmente con la seleccion
    ParamByName('fdesde').AsDate    := dteeddtefdesde.Date;
    ParamByName('fhasta').AsDate    := dteeddtefhasta.Date;
    Open;

    if zroqryinfrme_sup.RecordCount = 0 then
    begin
      MessageDlg('No se han encontrado registros en las Fechas seleccionadas.', mtWarning, [mbOK], 0);
      zroqryinfrme_sup.Close;
      dteeddtefdesde.SetFocus;
    end;
  end;

haciendo pruebas he seleccionado las 1.200 tiendas y el qry de resultados ha tardado menos de 4 segundos en calcular los datos de los partes (150 registros ahora mismo), teniendo en cuenta que es un mysql remoto vía adsl... como lo véis ??

lo que me da miedo es el día que la tabla de los partes tenga miles de registros y seleccionen todas las tiendas.... :(

se admiten sugerencias ;)

duilioisola 22-04-2010 18:40:39

Se me ocurre una tercera solución.
- Crea una tabla que contenga el código de las tiendas
- Muestras el Grid y dejas que el usuario seleccione las que desee.
- Recorre el grid e inserta las seleccionadas en la tabla.
- Luego puedes hacer un join o un select como el que te he mencionado más arriba.
Código SQL [-]
select campo1, campo2, campo3 from tbPrtesDia 
where (cdgotda in (select tienda from tabla_seleccion))

tgsistemas 22-04-2010 18:48:19

ummm así a primera vista, creo que en términos globales, el proceso será más lento, no??


La franja horaria es GMT +2. Ahora son las 12:06:10.

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