Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   SQL (https://www.clubdelphi.com/foros/forumdisplay.php?f=6)
-   -   consulta valores no consecutivos mismo campo (https://www.clubdelphi.com/foros/showthread.php?t=96799)

GINMARMENOR 24-07-2024 23:32:40

consulta valores no consecutivos mismo campo
 
Buenas, necesito hacer una consulta masiva dentro del mismo campo de una tabla en sql.

El ejemplo que quería poner para entendernos sería, que la tabla llamada 'MOTIVOS' tiene dos campos: año, HechoRelevante.

Quiero seleccionar 20 años de las 100 del siglo XX que yo elija no tienen que ser consecutivos, y sacar el hecho relevante de ese año elegido.

Al no ser consecutivos se complica y tengo que buscar uno a uno, podía usar un ListBox que contenga esos años que yo selecciono pero tendría que usar lines1, lines2,lines3 o bien edit como pongo en el ejemplo.

Código SQL [-]

              'select * motivos where año=' + Quotedstr (edit1.text) + 'and año=' Quotedstr (Edit2.text)

La pregunta es cómo puedo usar la línea SQL, para que no se haga tan larga, he buscado en internet y en el foro y no he encontrado ningún ejemplo que me dé respuesta.

mamcx 24-07-2024 23:49:56

Para esto se usa la cláusula:


Código SQL [-]
select * from motivos where año
IN
(2001, 1988, 1700, 2100)

mRoman 25-07-2024 00:57:20

Propuesta
 
Puede ser -como te lo menciona mamcx-, pero con una variante/parámetro

Código SQL [-]
select * from motivos where año
IN :anios

Lo cual el parámetro "anios", contendría una cadena como la que sigue
Cita:

(1979,2001,2010)
, el cual se llenaría mediante programación en una variable y se asignaría al parámetro:

Ejemplo:

Código Delphi [-]
procedure OnClick(Sender: TObject);
var
    cAnios : String;
begin
      cAnios:=cAnios+Edit1.Text+',';
end;

Y luego ejecutaría el procedimiento

Código Delphi [-]
procedure EjecutarProc(Sender: TObject);
var
    cAnios2 : String;
begin
       
       cAnios2:='('+cAnios+')'
       spEjecutar.Prepared;
       spEjecutar.ParamByName('ANIOS').AsString:=cAnios2
       spEjecutar.ExecProc;
end;


Algo mas o menos asi lo haría, no tengo a la mano Delphi para probar, pero podrías intentarlo y nos dices si mas o menos te sirvio.

Saludos.

GINMARMENOR 25-07-2024 14:33:40

En principio

Código SQL [-]
                    select * from motivos where año
                    IN
                    (2001, 1988, 1700, 2100)

Me da error y no puedo ejecutarlo


Por otro lado

Código SQL [-]
                      procedure OnClick(Sender: TObject);
                  var
                    cAnios : String;
                  begin
                    cAnios:=cAnios+Edit1.Text+',';
                 end;

yo la última línea la he modificado directamente a:

Código SQL [-]
                   cAnios:=cAnios+'1925'+'1955')

y me tomaría (19251955) como si fuera un número global.

He intentado los siguientes ejemplos:

Código SQL [-]
                     'select * motivos where año IN (1925,1955);

Código SQL [-]
                     'select * motivos where  año IN :cAnios;

Código SQL [-]
                     'select * motivos where año in: + Quotdstr (cAnios);

Ninguno de los de arriba funciona,

El único que funciona de momento, pero la cadena sería muy grande para 15 ó 20 años.

Código SQL [-]

              'select * motivos where año=' + Quotedstr ('1925') + 'OR año=' Quotedstr ('1955');

marco3k 25-07-2024 14:53:12

Lo que te escribió roman esta bien, pero veo que tu campo es texto porque dices que te funciono esto:
Código SQL [-]
'select * motivos where año=' + Quotedstr ('1925') + 'OR año=' Quotedstr ('1955');
Al poner "Quotedstr" le es estas diciendo a delphi que le pongas comillas simples, entonces prueba en tu consulta así:
Código SQL [-]
select * from motivos where año IN ('2000','2005','2012')

duilioisola 25-07-2024 15:30:25

Una tercera opción es tener una segunda tabla donde se rellenen los años seleccionados.

Código:

MOTIVOS
--------------------
AÑO  |  HECHORELEVANTE
1900 |  'AAAA'
1901 |  'BBBB'
1902 |  'CCCC'
...

SELECCION
--------------------
AÑO  |  SELECCIONADO
1900 |      X
1901 |      _
1902 |      X
...

y luego harías un join para ver solo los motivos de los años que estén marcados.

Código SQL [-]
SELECT M.* FROM MOTIVOS M
JOIN SELECCION S ON M.AÑO = S.AÑO
WHERE
S.SELECCION = 'X'
ORDER BY M.AÑO

De esta forma puede seleccionar solo un año o varios o todos...

mamcx 25-07-2024 17:37:09

Cita:

Empezado por marco3k (Mensaje 556837)
Lo que te escribió roman esta bien, pero veo que tu campo es texto


Eso debería ser un integer...

GINMARMENOR 25-07-2024 18:13:45

Buenas de nuevo, y gracias en serio.

La siguiente secuencia funciona BIEN que es la que MRoman, por un lapsus dije no.

Código SQL [-]
          select * motivos where año IN (1925,1955);

Pero el texto completo es el siguiente que no lo puse por simplificar:

Código SQL [-]
           ibQueryMotivos.close;
           IbQueryMotivos.Clear;
           IbQueryMotivos.text:='select * motivos where año IN (1925,1955)';
           IbQueryMotivos.open;

Con esto puedo meter los datos filtrados en un dbgrid, stringGrid, Rave Reports, etc etc sin problemas pero al estar en unas comillas sólo puedo elegir los años (1925, 1955, etc.etc) en modo diseño y no en modo ejecucion, lo que necesitaría es meter los años en un Listbox, en una Variable u otro contenedor, y de ahí diseñar el Query para que sólo salgan los años que necesito.

mRoman 25-07-2024 18:42:34

Cita:

Empezado por GINMARMENOR (Mensaje 556842)
Buenas de nuevo, y gracias en serio.

La siguiente secuencia funciona BIEN que es la que MRoman, por un lapsus dije no.

Código SQL [-]
          select * motivos where año IN (1925,1955);

Pero el texto completo es el siguiente que no lo puse por simplificar:

Código SQL [-]
           ibQueryMotivos.close;
           IbQueryMotivos.Clear;
           IbQueryMotivos.text:='select * motivos where año IN (1925,1955)';
           IbQueryMotivos.open;

Con esto puedo meter los datos filtrados en un dbgrid, stringGrid, Rave Reports, etc etc sin problemas pero al estar en unas comillas sólo puedo elegir los años (1925, 1955, etc.etc) en modo diseño y no en modo ejecucion, lo que necesitaría es meter los años en un Listbox, en una Variable u otro contenedor, y de ahí diseñar el Query para que sólo salgan los años que necesito.

Hola...una observación: En la propiedad TEXT del "ibQuery", no te hace falta "FROM" en la sentencia SELECT??... "select * FROM motivos..." y otra obervación, el campo AÑO te permite la "Ñ"??...la verdad nunca he usado la Ñ en los campos que creo en Firebird, no sé si lo permita. En realidad los declaro -en el caso del año- como ANIO.

Ahora, creo que el componente del IBQuery, quedaría asi:

Código Delphi [-]
IBQueryMotivos.SQL.Clear;
IBQueryMotivos.SQL.Add('select * from motivos where año in '+ANIOS2);
IBQueryMotivos.Open;

Para cuando se ejecute las instrucciones anteriores, ya deberá traer datos la variable ANIOS2:
Código:

(1973,1910,1917)
Concatenando los paréntesis al inicio y al final de la cadena, que también deberas inlcuir en la cadena la coma "," para separar un año del otro

Te envío un ejemplo de como lo uso
Código Delphi [-]
              aQrySic.SQL.LoadFromFile(ExtractFilePath(Application.ExeName)+'\SQLS\SCA_SOME_PROMOTORES.SQL');
              aQrySic.SQL.Add('    and pmt_numero in '+cPromotor);
              aQrySic.SQL.Add(' order by lec_numero, numero_tarjeta');
              aQrySic.Open;

Aqui lleno la variable "cPromotor" con las claves de algunos promotores que el usuario ha seleccionado:

Código Delphi [-]
              2: begin // SELECCIONA ALGUNOS PROMOTORES
                    qryLecherias.DisableControls;
                    BM:=qryLecherias.Bookmark;
                    try
                        with dbgLecherias.DataSource.DataSet do
                        for i:=0 to dbgLecherias.SelectedRows.Count-1 do
                        begin
                           qryLecherias.Bookmark:=dbgLecherias.SelectedRows.Items[i];
                           cPromotor:=cPromotor+qryLecherias.fieldbyname('DATO1').AsString;
                            if i<>dbgLecherias.SelectedRows.Count-1 then
                            begin
                               cPromotor:=cPromotor+',';
                            end;
                        end;
                    finally
                        qryLecherias.Bookmark:=BM;
                        qryLecherias.EnableControls;
                    end;
                    if cPromotor<>'' then
                    begin
                        cPromotor:='('+cPromotor+')';
                        aQrySic.SQL.Clear;
                        aQrySic.SQL.LoadFromFile(ExtractFilePath(Application.ExeName)+'\SQLS\SCA_SOME_PROMOTORES.SQL');
                        aQrySic.SQL.Add('    and pmt_numero in '+cPromotor);
                        aQrySic.SQL.Add(' order by lec_numero, numero_tarjeta');
                    end;
                 end;

Usé la sentencia CASE en programación para seleccionar la opción 0,1 o 2 de un combo que el usuario selecciona para saber que tipo de procesamiento se va a realizar, estos serían los ITEMS del combo:

Código:

Todas las lecherias todos los promotores
Algunas Lecherias
Algunos promotores social

Espero te sirva esta orientación.

Saludos.

GINMARMENOR 25-07-2024 20:37:44

En relación a:

Cita:

Hola...una observación: En la propiedad TEXT del "ibQuery", no te hace falta "FROM" en la sentencia SELECT??... "select * FROM
motivos..." y otra obervación, el campo AÑO te permite la "Ñ"??...la verdad nunca he usado la Ñ en los campos que creo en
Firebird, no sé si lo permita. En realidad los declaro -en el caso del año- como ANIO.

Tienes razón FROM lo olvidé en la sintaxis en el foro, pero está escrito en el código, y tambén la 'Ñ' no la permite, uso N
era por usar un lenguaje natural.

Lo cierto es que como he dicho funciona:

Código SQL [-]
                          ibQueryMotivos.close;
                          IbQueryMotivos.Clear;
                          IbQueryMotivos.add('select * from motivos where anio IN (1925,1955,1920)';
                          IbQueryMotivos.open;

y no

Código SQL [-]
                        var
                            anios:string;

                        begin
                          anios:=(1925,1955,1920);
                        
                          IBQueryMotivos.SQL.Clear;
                          IBQueryMotivos.SQL.Add('select * from motivos where año in '+ANIOS);
                          IBQueryMotivos.Open;

He intentando 200 maneras pero no lo consigo,

He intentando el procedimiento que me pones:


Código SQL [-]
procedure OnClick(Sender: TObject);
var
    cAnios : String;
begin
      cAnios:=cAnios+Edit1.Text+',';
end;


procedure EjecutarProc(Sender: TObject);
var
    cAnios2 : String;
begin
       
       cAnios2:='('+cAnios+')'
       spEjecutar.Prepared;
       spEjecutar.ParamByName('ANIOS').AsString:=cAnios2
       spEjecutar.ExecProc;
end;

Pero no sé ejecutarlo, Gracias, mañana intentaré con la mente más fresca pasar una variable a parámetro a ver.

marco3k 25-07-2024 20:44:14

Código Delphi [-]
var
    anios:string;

begin
  anios:=(1925,1955,1920);

  IBQueryMotivos.SQL.Clear;
  IBQueryMotivos.SQL.Add('select * from motivos where año in '+ANIOS);
  IBQueryMotivos.Open;

Eso de arriba debe ser así y me comentas como te fue:
Código Delphi [-]
var
    anios:string;

begin
  anios:='1925,1955,1920';

  IBQueryMotivos.SQL.Clear;
  IBQueryMotivos.SQL.Add('select * from motivos where año in ('+anios+')');
  IBQueryMotivos.Open;

Lo demás es hacer un bucle para coger los años, Roman ya te dio un ejemplo.

cloayza 25-07-2024 20:53:23

Estimado GINMARMENOR.

Le propongo otra opción...

Código Delphi [-]
ibQueryMotivos.close;
IbQueryMotivos.Clear;
IbQueryMotivos.text:='Select * From where Position(Cast(año As Varchar(4)), :Lista_Anos)>0';
IbQueryMotivos.ParamByName('Lista_Anos').AsString:='1925|1955|...|...|...';
IbQueryMotivos.open;

Aquí solo debería generar la lista de años junto con un separador...Asumo que el año es de 4 digitos...

Saludos cordiales

mRoman 25-07-2024 22:41:39

Cita:

Empezado por GINMARMENOR (Mensaje 556844)
En relación a:



Tienes razón FROM lo olvidé en la sintaxis en el foro, pero está escrito en el código, y tambén la 'Ñ' no la permite, uso N
era por usar un lenguaje natural.

Lo cierto es que como he dicho funciona:

Código SQL [-]
                          ibQueryMotivos.close;
                          IbQueryMotivos.Clear;
                          IbQueryMotivos.add('select * from motivos where anio IN (1925,1955,1920)';
                          IbQueryMotivos.open;

y no

Código SQL [-]
                        var
                            anios:string;

                        begin
                          anios:=(1925,1955,1920);
                        
                          IBQueryMotivos.SQL.Clear;
                          IBQueryMotivos.SQL.Add('select * from motivos where año in '+ANIOS);
                          IBQueryMotivos.Open;

He intentando 200 maneras pero no lo consigo,

He intentando el procedimiento que me pones:


Código SQL [-]
procedure OnClick(Sender: TObject);
var
    cAnios : String;
begin
      cAnios:=cAnios+Edit1.Text+',';
end;


procedure EjecutarProc(Sender: TObject);
var
    cAnios2 : String;
begin
       
       cAnios2:='('+cAnios+')'
       spEjecutar.Prepared;
       spEjecutar.ParamByName('ANIOS').AsString:=cAnios2
       spEjecutar.ExecProc;
end;

Pero no sé ejecutarlo, Gracias, mañana intentaré con la mente más fresca pasar una variable a parámetro a ver.

Bueno...en vez de "ExecProc", usa "Open", ademas de que este ejemplo no estaba seguro de q funcionara, mejor usa el ejemplo mas amplio q te envié....ese ya esta probado q funciona!.

Saludos.

mRoman 25-07-2024 22:45:17

En este código deberás hacer un cambio:

Código Delphi [-]
var
                            anios:string;

                        begin
                          anios:=(1925,1955,1920); // asi no debería funcionarte
                          anios:='(1925,1955,1920)';  //haz este cambio, deberán estar, toda la cadena con los paréntesis también, encerrado en comillas simples.
                        
                          IBQueryMotivos.SQL.Clear;
                          IBQueryMotivos.SQL.Add('select * from motivos where año in '+ANIOS);
                          IBQueryMotivos.Open;

Y otra cosa, mejor mandános tu código para ver como le estas haciendo...y aqui entre todos te ayudamos a resolverlo de la mejor manera.

Saludos.

duilioisola 26-07-2024 08:22:45

Yo lo que veo mal es el procedimiento que utilizas para concatenar los valores.

Código Delphi [-]
procedure OnClick(Sender: TObject);
var
    cAnios : String;
begin
   cAnios := cAnios + Edit1.Text + ',';
end;
Esto trabaja sobre una variable local, la cual se pierde después de terminar el procedimiento.
Incluso si fuera una variable global "," te dejaría una coma al final.

Deberías hacerlo así:

Código Delphi [-]
// cAnios debe ser global a la unidad para poder compartirla entre los diferentes procedimientos
var 
  cAnios : string;

procedure OnClick(Sender: TObject);
begin
   // Solo agrego la "," si no es el primer elemento
   if (cAnios = '') then
      cAnios := cAnios + Edit1.Text + ','
   else
      cAnios := cAnios + ',' + Edit1.Text;
end;

procedure BotonInicializarOnClick(Sender: TObject);
begin
   // Inicializo cAnios para volver a empezar con proceso de selección 
   cAnios := '';
end;

procedure EjecutarProc(Sender: TObject);
begin
   // cAnios debería tener valores separados por coma.

   if (cAnios > '') then
   begin
      IBQueryMotivos.SQL.Clear;
      IBQueryMotivos.SQL.Add('select * from motivos where año in (' + cAnios + ')');
      IBQueryMotivos.Open;
   end
   else
      ShowMessage('No se han seleccionado años');
end;

begin
   // Inicializo cAnios
   cAnios := '';
   [...]
end;

GINMARMENOR 26-07-2024 19:52:35

Perdonar la tardanza, pero estaba saturado ayer.

He probado las soluciones que me mandáis y FUNCIONAN, BIENNNNNNNN.


Código SQL [-]
                         var
                              anios:string;


                        Begin
                          anios:='(1925,1955,1920)';  
                       
                          IBQueryMotivos.SQL.Clear;
                          IBQueryMotivos.SQL.Add('select * from motivos where año in '+ANIOS);
                          IBQueryMotivos.Open;
                        end;

y Lógicamente también así:


Código SQL [-]

procedure Button1click(Sender: TObject);

var
    cAnios : String;

begin
   cAnios := cAnios + Edit1.Text + ',';

 // cAnios debería tener valores separados por coma.

   
   begin

      IBQueryMotivos.SQL.Clear;
      IBQueryMotivos.SQL.Add('select * from motivos where año in (' + cAnios + ')');
      IBQueryMotivos.Open;

   end
   else
      ShowMessage('No se han seleccionado años');
end;


Como me has pedido MRoman, mi código era meter en un StringGrid ó en un QuickReport, Rave Report, etc etc, sólo aquellos años que yo eligiera aleatoriamente, sin tener que ser todos los que son menores ó mayores que tal año, que eso sería más fácil.

Por lo que mi código quedaría así:


Código SQL [-]

procedure tform1.Button1Click (sender:tobjet);

var
      anios1,anios2,anios3:string;
      x,c:Integer;

begin
       c:=1
       for x:=1 to Memo1.Lines.Count - 1 do
            begin
              anios1:=Memo1.Lines[x];
              anios2:=anios2+anios1+ ',';
              anios3:=anios2+'0';
       end;

       with tqueryMotivos do
       close;
       sql.clear;
       sql.add('select anio,Motivo from Motivos where Motivo in '(' + anios3 + ')';
       open;

       while not IbQueryMotivo.eof do
                begin
                   Stringgrid1.cells[c]:=IbQueryMotivo.FieldByname(anio).AsString;
                   StringGrid1.Cells[c]:=IbQueryMotivo.FieldByname(Motivo).AsString;
                   inc(c);
                   IbQueryMotivo.next;
                 end;

Bueno esto sería acabado el código entero simplificado a lo máximo, he utilizado para rellenar y sacar los datos finales un striggrid
He utilizado un Memo1, en vez de Edit, por comodidad y el Memo me deja introducir los años más cómodamente,
He utilizado tres Anios1,Anios2,Anios3,
donde el primero cojo, la primera línea del Memo
el Segundo cojo Anios1 + el Acumulado del Anios2, (1925,1955,1920,) y se quedaría así con una coma inoportuna ahí.
y Tercero cojo el Anios 2 entero, y como el Anios2 siempre acababa en ',' o siempre empezaba ',' no había forma de quitarla pues
le añadido en el anios3 un '0' y quedaría así (1925,1955,1920,0) el 0 nunca va representar ningún año y no me altera en nada el
resultado y así no me da error.

Lo mismo se puede hacer más simple, estoy abierto a aprender, y reducirlo al máximo, vosotros sois mucho mas expertos que yo.

Así que no me queda más que agredecer, el interés y las soluciones que me habéis dado, con esto se me ha abierto un abanico
muy grande para escoger dentro de un campo de forma aleatoria. Muchísimas Gracias.

cloayza 26-07-2024 20:28:35

Estimado Colega, si está utilizando un TMemo, le sugiero el siguiente cambio...

Código Delphi [-]
procedure tform1.Button1Click (sender:tobjet);

var
      anios1,anios2,anios3:string;
      x,c:Integer;

begin
       c:=1
       {for x:=1 to Memo1.Lines.Count - 1 do
            begin
              anios1:=Memo1.Lines[x];
              anios2:=anios2+anios1+ ',';
              anios3:=anios2+'0';
       end;
       }
       Memo1.Lines.Delimiter:=',';
       anios3:=Memo1.Lines.DelimitedText;

       with tqueryMotivos do
       close;
       sql.clear;
       sql.add('select anio,Motivo from Motivos where Motivo in '(' + anios3 + ')';
       open;

       while not IbQueryMotivo.eof do
                begin
                   Stringgrid1.cells[c]:=IbQueryMotivo.FieldByname(anio).AsString;
                   StringGrid1.Cells[c]:=IbQueryMotivo.FieldByname(Motivo).AsString;
                   inc(c);
                   IbQueryMotivo.next;
                 end;

Saludos cordiales

GINMARMENOR 27-07-2024 11:30:04

Ok, va cojonudo, ahorramos bucle y dos variables.

Ok, He utilizado Memo1, por rapidez y sencillez, no sé si habrá otro componente más apropiado.

Gracias.


La franja horaria es GMT +2. Ahora son las 11:14:27.

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