Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   SQL (https://www.clubdelphi.com/foros/forumdisplay.php?f=6)
-   -   Operador IN en campos VARCHAR O STRING (https://www.clubdelphi.com/foros/showthread.php?t=96802)

GINMARMENOR 28-07-2024 20:24:00

Operador IN en campos VARCHAR O STRING
 
Buenas tardes,

Tengo un problema con el operador IN, ya que si me funciona en campos INTEGER, pero no hace lo mismo en campos STRING Ó VARCHAR.

Digamos que poniendo un ejemplo sencillo, dispongo de una Tabla llamada INVENTARIO de libros con tres campos:

EXIST: integer
GENERO: varchar
TITULOS: varchar

Utilizo la siguiente consulta y me da bien el resultado sin problema, me devuelven Generos que tienen 5,3,8 en existencias.
Código SQL [-]
               var
                   NumExist:string;


                        Begin
                          NumExist:='(5,3,8)';  
                       
                          IBQueryInvent.SQL.Clear;
                          IBQueryInvent.SQL.Add('select * from INVENTARIO where EXIST IN '+ NumExist);  // EXIST ES TIPO INTEGER
                          IBQueryInvent.Open;
                        end;



En cambio si hago lo mismo con el campo GENERO que es tipo VARCHAR

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


                        Begin
                          TipoGen:='(Comedia,Drama)';  
                       
                          IBQueryInvent.SQL.Clear;
                          IBQueryInvent.SQL.Add('select * from INVENTARIO where Genero IN '+ TipoGen);  // GENERO es tipo VARCHAR
                          IBQueryInvent.Open;
                        end;

'

En este caso me da el siguiente error: 'Attemp to execute an unprepared dynamic SQL statement.

En caso de que el formato lo cambiara por:


TipoGen:='(''Comedia,Drama'')'; el error sería 'Conversion error from string 'Comedia,Drama'



En cambio utilizando sólo uno si funciona, pero necesito que sean varios y aleatorios.

TipoGen:='(''Comedia'')'; si funciona

He intentado varias posibilidades, en internet, en este foro y no distinguen entre campo tipo varchar o tipo Integer.

lucho6007 28-07-2024 23:34:01

Hola, buenas tardes!
Podrías probar con el siguiente código:

Código Delphi [-]
var
  TipoGen:string;
begin
  TipoGen:= '(' + QuotedStr('Comedia') + ',' + QuotedStr('Drama') + ')';
  IBQueryInvent.SQL.Clear;
  IBQueryInvent.SQL.Add('select * from INVENTARIO where Genero IN '+ TipoGen);  // GENERO es tipo VARCHAR 
  IBQueryInvent.Open;
end;

duilioisola 29-07-2024 11:18:41

Cada string tiene que estar entrecomillado.

Código Delphi [-]
// TipoGen debe tener cada string entrecomillado: Ej.: ('Comedia', 'Drama')
TipoGen:='(''Comedia'', ''Drama'')';

// El SQL quedaría
// select * from INVENTARIO where Genero IN ('Comedia', 'Drama')

GINMARMENOR 29-07-2024 23:07:16

Gracias funcionan los dos códigos aunque me decante por el que no aparece 'Quotedstr', y el código se quedaría como sigue pero leyendo en un Memo y así en modo de ejecución elegir los distintos generos que quiera.

Código SQL [-]
var
  TipoGen,TipoGen1,TipoGen2:string;
  x:integer;
begin
  for x:=1 to Memo1.Lines.count - 1 do;
      begin

        TipoGen:=Memo1.Lines[x];

        TipoGen1:=TipoGen1+''''+TipoGen+''' , ';

      end;

        TipoGen2:=TipoGen1+'''0'''; 

  IBQueryInvent.SQL.Clear;

  IBQueryInvent.SQL.Add('select * from INVENTARIO where Genero IN '+ '(' + TipoGen2 + ')';  // GENERO es tipo VARCHAR 

  IBQueryInvent.Open;
end;

El último TipoGen2, lo año por que la cadena siempre acaba en coma, y así le añado un 0 para que lea un genero que nunca exista y me permita que funcione.

NOTA: En este caso el tema de comillas, la verdad que es increíble pero funciona.

duilioisola 30-07-2024 08:11:22

Tres cosas:

1. Las líneas de un memo empiezan con el índice 0. Supongo ue en el FOR empiezas con x := 1 porque la primera es un título. Si no es así, estás perdiendo un elemento.

2. Si no tienes contenido en el Memo, no deberías filtrar...

3. Una forma más elegante (y con menos líneas) es fabricar el SQL en vez de hacerlo en variables para después concatenarlas.
(siempre teniendo en cuenta que la primera línea del memo hay que ignorarla como haces en tú ejemplo)
Código Delphi [-]
{
Esto construye el siguiente SQL
    select * from INVENTARIO
    where Genero IN (
    '123',
    '456',
    '789',
    '0' )
}
var
  x:integer;
begin
  IBQueryInvent.SQL.Clear;

  IBQueryInvent.SQL.Add('select * from INVENTARIO ');
  // Si hay contenido en el memo
  if (Memo1.Lines.Count > 1) then
  begin
    IBQueryInvent.SQL.Add('where Genero IN ( ');
    for x:=1 to Memo1.Lines.count - 1 do;
       IBQueryInvent.SQL.Add('''' + Memo1.Lines[x] + ''' , ');
    IBQueryInvent.SQL.Add('''0'' ) ');
  end;
  
  IBQueryInvent.Open;
end;

Yo prefiero utilizar WITH..DO para evitar repetir el componente en cada línea.
Código Delphi [-]
var
  x:integer;
begin
  with IBQueryInvent do
  begin
    SQL.Clear;
    SQL.Add('select * from INVENTARIO ');
    // Si hay contenido en el memo
    if (Memo1.Lines.Count > 1) then
    begin
      SQL.Add('where Genero IN ( ');
      for x:=1 to Memo1.Lines.count - 1 do;
         SQL.Add('''' + Memo1.Lines[x] + ''' , ');
      SQL.Add('''0'' ) ');
    end;
    
    Open;
  end;
end;

Y mi preferida, evitando poner un elemento que no existe:
1. Agrego la primera condición, si existe
2. Agrego el resto con una coma delante.
Código Delphi [-]
{
Esto construye el siguiente SQL
    select * from INVENTARIO
    where Genero IN (
    '123'
    ,'456'
    ,'789'
    )
}
var
  x:integer;
begin
  with IBQueryInvent do
  begin
    SQL.Clear;
    SQL.Add('select * from INVENTARIO ');
    // Si hay contenido en el memo
    if (Memo1.Lines.Count > 1) then
    begin
      SQL.Add('where Genero IN ( ');
         SQL.Add('''' + Memo1.Lines[1] + '''');
      // Siguientes lineas
      for x:=2 to Memo1.Lines.count - 1 do;
         SQL.Add(', ''' + Memo1.Lines[x] + '''');
      SQL.Add(')');
    end;
    
    Open;
  end;
end;

cloayza 30-07-2024 15:18:00

Estimado GINMARMENOR, en otro post le sugerí este cambio...

Código Delphi [-]
var
  TipoGen,TipoGen1,TipoGen2:string;
  x:integer;
begin
{  for x:=1 to Memo1.Lines.count - 1 do;
      begin

        TipoGen:=Memo1.Lines[x];

        TipoGen1:=TipoGen1+''''+TipoGen+''' , ';

      end;

      TipoGen2:=TipoGen1+'''0'''; 
       }
      Memo1.Lines.Delimiter:=',';
      TipoGen2:=Memo1.Lines.DelimitedText;

  IBQueryInvent.SQL.Clear;

  IBQueryInvent.SQL.Add('select * from INVENTARIO where Genero IN '+ '(' + TipoGen2 + ')';  // GENERO es tipo VARCHAR 

  IBQueryInvent.Open;
end;
Saludos cordiales

GINMARMENOR 30-07-2024 22:27:41

Lo primero que miré cloayza , fue utilizar tu código ya que se reducía increíblemente

Código SQL [-]
      Memo1.Lines.Delimiter:=',';
      TipoGen2:=Memo1.Lines.DelimitedText;

Le di bastantes vueltas pero no había forma por eso abrí otro hilo. La diferencia está en que cuando me lo sugeriste estábamos trabajando con un campo INTEGER (buscando años), pero ahora necesitaba buscar en un campo VARCHAR (STRING), y hay que colocar comillas entre cada texto que se busca y hay que tener cuidado en colocarlas ya que son bastantes no basta con una comilla al principio y otra al final, por eso en campos VARCHAR no funciona, a no se que haya otra fórmula parecida.

Duilioisola, aún no he pillado la lógica de las camillas, pero funciona.

duilioisola 31-07-2024 08:48:33

Cita:

Empezado por GINMARMENOR (Mensaje 556889)
Duilioisola, aún no he pillado la lógica de las camillas, pero funciona.


La lógica es la siguiente:


Código:

SELECT * FROM TABLA
WHERE
CAMPO IN (COMPARACION_1, COMPARACION_2, COMPARACION_3, ...)


En un SQL si quieres poner un número, lo agregas y ya está.
SQL entiende que mientras vea números, el punto y el signo "+" o "-" debe interpretarlo como número, hasta que encuentre un separador (espacio, ";" indicando final de línea, ")" indicando final de función, etc.)


Si es un texto, debes entrecomillarlo para indicar donde empieza y donde termina el texto. SQL sabrá que hasta que no encuentre otra comilla, todos esos caracteres forman parte de un mismo string.

Por ejemplo:
Código:

'Garcia, Juan Carlos' es un string.
 |-----------------|

'Garcia', 'Juan', 'Carlos' son 3 strings.
 |----|    |--|    |----|

+123.45 es un numero positivo con decimales.
|-----|

-123 45      es un error, puesto que hay u número y luego un espacio seguido de otro número.
|--| [ERROR|

Espero que esto aclare un poco las cosas.

GINMARMENOR 31-07-2024 22:19:16

ok, gracias,


La franja horaria es GMT +2. Ahora son las 11:15:35.

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