Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > SQL
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 28-07-2024
GINMARMENOR GINMARMENOR is offline
Miembro
 
Registrado: feb 2016
Posts: 70
Poder: 9
GINMARMENOR Va por buen camino
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.
Responder Con Cita
  #2  
Antiguo 28-07-2024
lucho6007 lucho6007 is offline
Miembro
 
Registrado: ene 2009
Ubicación: Junín, pcia de BsAs, Argentina
Posts: 81
Poder: 16
lucho6007 Va por buen camino
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;

Última edición por lucho6007 fecha: 28-07-2024 a las 23:35:28. Razón: copié y pegué el código y se veía mal :(
Responder Con Cita
  #3  
Antiguo 29-07-2024
Avatar de duilioisola
[duilioisola] duilioisola is offline
Miembro Premium
 
Registrado: ago 2007
Ubicación: Barcelona, España
Posts: 1.757
Poder: 21
duilioisola Es un diamante en brutoduilioisola Es un diamante en brutoduilioisola Es un diamante en bruto
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')
Responder Con Cita
  #4  
Antiguo 29-07-2024
GINMARMENOR GINMARMENOR is offline
Miembro
 
Registrado: feb 2016
Posts: 70
Poder: 9
GINMARMENOR Va por buen camino
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.
Responder Con Cita
  #5  
Antiguo 30-07-2024
Avatar de duilioisola
[duilioisola] duilioisola is offline
Miembro Premium
 
Registrado: ago 2007
Ubicación: Barcelona, España
Posts: 1.757
Poder: 21
duilioisola Es un diamante en brutoduilioisola Es un diamante en brutoduilioisola Es un diamante en bruto
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;

Última edición por duilioisola fecha: 30-07-2024 a las 08:16:50.
Responder Con Cita
  #6  
Antiguo 30-07-2024
cloayza cloayza is offline
Miembro
 
Registrado: may 2003
Ubicación: San Pedro de la Paz, Chile
Posts: 927
Poder: 23
cloayza Tiene un aura espectacularcloayza Tiene un aura espectacular
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
Responder Con Cita
  #7  
Antiguo 30-07-2024
GINMARMENOR GINMARMENOR is offline
Miembro
 
Registrado: feb 2016
Posts: 70
Poder: 9
GINMARMENOR Va por buen camino
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.
Responder Con Cita
  #8  
Antiguo 31-07-2024
Avatar de duilioisola
[duilioisola] duilioisola is offline
Miembro Premium
 
Registrado: ago 2007
Ubicación: Barcelona, España
Posts: 1.757
Poder: 21
duilioisola Es un diamante en brutoduilioisola Es un diamante en brutoduilioisola Es un diamante en bruto
Cita:
Empezado por GINMARMENOR Ver Mensaje
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.

Última edición por duilioisola fecha: 31-07-2024 a las 08:54:50.
Responder Con Cita
  #9  
Antiguo 31-07-2024
GINMARMENOR GINMARMENOR is offline
Miembro
 
Registrado: feb 2016
Posts: 70
Poder: 9
GINMARMENOR Va por buen camino
ok, gracias,
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Dbgrid solo muestra campos tipo INT, campos varchar no los muestra pollo_c C++ Builder 2 10-09-2017 21:42:47
Sin campos Varchar en el TSQLQery Chandra_ Lazarus, FreePascal, Kylix, etc. 6 27-09-2012 23:42:20
sumar dos campos varchar richy08 MySQL 5 08-01-2008 13:17:39
trim en campos varchar galmacland SQL 3 12-03-2005 02:40:23
Concatenar campos varchar en triggers Iceman Firebird e Interbase 1 14-06-2004 21:24:26


La franja horaria es GMT +2. Ahora son las 14:19:30.


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
Copyright 1996-2007 Club Delphi