Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Desactivar parametro en query (https://www.clubdelphi.com/foros/showthread.php?t=89104)

Kenobi 27-09-2015 04:03:19

Desactivar parametro en query
 
Hola amigos, el problema que me ocupa es el siguiente, muchas veces creamos datamodulos y lo vamos llenando de componentes query para esto para aquellos etc. por ejemplo un query con todos los campos de la tabla, otro con la cuenta de todos a modo de resumen. bien en ese orden de ideas y pensando en que es bueno crear componentes reutilizables les expongo lo siguiente .....

supongamos que tengo una tabla proyectos que tiene los proyectos con sus categorias, luego para saber cuantos proyectos por categoria hay pues en un query :
Código Delphi [-]
select proyectos,categorias,count(categorias)
from proyectos
group by categorias

ahora bien suponiendo que quiero saber cuantas categorias tiene un proyecto en particular pues:
Código Delphi [-]
select proyectos,categorias,count(categorias)
from proyectos
where proyecto=:miParametro
group by categorias

bien hasta ahora son dos componentes query que hacen lo mismo pero uno con parametros y el otro no pues lo que quisiera hacer es uno solo que segun si le paso parametro o no me mande los resultados, ejemplo:

Código Delphi [-]

if length(miParametro)>1 then query.params.paramvalues['miParametro']:=miParametro
else 'ACA QUE NO TOME EN CUENTA EL PARAMETRO O UTILIZE UN COMODIN'  // miParametro:='%' o '*' "ninguno funciona"

en todo caso se que construyendo la consulta en tiempo de ejecucion:
Código Delphi [-]
query.slq.add('select * from tabla blabablabla....')
se podria pero me gustaria hacerlo en tiempo de diseño, o tambien quitando el paramentro del query a aplicandolo como filtro, pero esta opción (que ya la aplique) es mas lenta porque se trae todos los proyectos para luego filtrar y por otro lado si luego olvidas que la data esta filtrada y haces un insert puedes duplicar registros(pero esto es harina de otro costal)

ojala haya logrado explicarme y sean tan amables de orientarme en esto ....

Gracias

Kenobi 27-09-2015 04:06:05

otra alternativa es ...
 
esta es mas loca aun porque depende de al posición del texto en particular dentro del sql del query :

Código Delphi [-]
  if miParametro = '' then query.SQL.Strings[linea_donde_esta_el_where]:=''
                 else query.Params.ParamValues['miParametro']:=miParametro;

funciona, pero es peor el remedio que la enfermedad ....

AgustinOrtu 27-09-2015 04:30:53

No lo probe nunca pero creo que se podria hacer algo como

Código SQL [-]
SELECT * FROM Table
WHERE Campo = :Param AND Campo <> NULL

Código Delphi [-]
  qry.ParamByName('Param').Clear;
  qry.ParamByName('Param').Value := NULL; // uses Variants
  qry.ParamByName('Param').SetNull;

No estoy seguro cual de las 3 alternativas de arriba es valida, creo que dependen de los componentes/motor bd.

PD: El metodo SetNull no estoy seguro si existe o me lo saque de la chistera :)

Kenobi 27-09-2015 04:43:28

No funciona
 
Hola gracias por tu respuesta, pero no funciona ninguna de las opciones, tanto clear como value:=null devuelven el query vacio quiere decir que no lo usa como comodin de ALL(% , *)

gracias y setNUll en efecto no existe JEJEJEJE

AgustinOrtu 27-09-2015 04:52:05

Bueno, admito que me equivoque :) eso pasa por hacerlo de memoria y no probarlo jaja

Edito:

Me retracto nuevamente lo que postie no sirve :(

ecfisa 27-09-2015 11:57:05

Hola Kenobi.
Cita:

Empezado por Kenobi (Mensaje 497213)
...
Código SQL [-]
select proyectos,categorias,count(categorias)
from proyectos
where proyecto=:miParametro
group by categorias

Lo primero que me llama la atención es que la consulta anterior funcione sin haber incluído la columna "proyectos" en la declaración GROUP BY ...

Para reutilizar el mismo query, se me ocurre que podrías hacer algo similar a este ejemplo:
Código Delphi [-]
procedure UnDataModule.CountCategories(const Categoria: string); 
begin
  qyCat.Close;

  qyCat.SQL.Clear;
  qyCat.SQL.Add('SELECT PROYECTO, COUNT(CATEGORIAS)');
  qyCat.SQL.Add('FROM PROYECTOS');
  qyCat.SQL.Add('WHERE PROYECTO = :PARAM');
  qyCat.SQL.Add('GROUP BY PROYECTO');

  if Categoria = EmptyStr then
    qyCat.SQL.Delete(2)
  else
    qyCat.parameters.ParamByName('PARAM').Value := Categoria;

  qyCat.Open;
end;

Saludos :)

Kenobi 27-09-2015 12:18:01

Estoy en busca de una opcion mejor, si es que existe
 
Cita:

Empezado por ecfisa (Mensaje 497222)
Hola Kenobi.

Lo primero que me llama la atención es que la consulta anterior funcione sin haber incluído la columna "proyectos" en la declaración GROUP BY ...

tienes razon, ese query no funciona ya que lo invente en el momento para no mostrar el codigo del query real, por aquello de proteger el codigo en producción, pero es muy similar.

Cita:

Empezado por ecfisa (Mensaje 497222)
Para reutilizar el mismo query, se me ocurre que podrías hacer algo similar a este ejemplo:
Código Delphi [-]
procedure UnDataModule.CountCategories(const Categoria: string); 
begin
  qyCat.Close;

  qyCat.SQL.Clear;
  qyCat.SQL.Add('SELECT PROYECTO, COUNT(CATEGORIAS)');
  qyCat.SQL.Add('FROM PROYECTOS');
  qyCat.SQL.Add('WHERE PROYECTO = :PARAM');
  qyCat.SQL.Add('GROUP BY PROYECTO');

  if Categoria = EmptyStr then
    qyCat.SQL.Delete(2)
  else
    qyCat.parameters.ParamByName('PARAM').Value := Categoria;

  qyCat.Open;
end;

así lo tengo hecho pero como mencione estoy buscando una alternativa para no crear el codigo del query( query.sql.add(codigo sql)) en tiempo de ejecución, me apete algo como :
Código Delphi [-]
if length(param) > 1 then qyCat.parameters.ParamByName('PARAM').Value := Param
                           else 'DESACTIVO EL PARAMETRO SIN DESTRUIRLO, BORRARLO PARA QUE LA SENTENCIA SIGA IGUAL A LA CREADA EN DISEÑO, PERO
                                SE EJECUTE SIN EL PARAMETRO, AL MENOS EN ESTA LLAMADA'


Gracias por sus respuestas ....

P.D AgustinOrtu, así sea de memoria y no haya funcionado, en verdad agradezco tu intención y tu tiempo para responder, saludos

AgustinOrtu 27-09-2015 19:31:07

Estaba convencido de que se podia :)

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
begin
  ADOQuery1.Close;
  if Edit1.Text <> '' then
    ADOQuery1.Parameters.ParamByName('ParamId').Value := Edit1.Text
  else
    ADOQuery1.Parameters.ParamByName('ParamId').Value := NULL;
  ADOQuery1.Open;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ADOQuery1.SQL.Text := ' SELECT * FROM Productos WHERE Id = IsNull(:ParamId, Id) ';
  ADOQuery1.Prepared := True;
end;



Saludos :)

Casimiro Notevi 27-09-2015 19:42:23

Cita:

Empezado por Kenobi (Mensaje 497223)
tienes razon, ese query no funciona ya que lo invente en el momento para no mostrar el codigo del query real, por aquello de proteger el codigo en producción, pero es muy similar.

-Señor policía, ¿puede ayudarme?
+Sí, dígame lo que le ocurre.
-No puedo, es secreto.
:confused::confused::confused:
:D

Kenobi 27-09-2015 20:13:17

En efecto funciona
 
Barbaro ....
solo 2 cosas, para mySql es IfNull() lo cual es un pequeño problema porque la idea es mantener el codigo mas independiente del manejador, por otro lado me imagino que sera propio del uso de la funcion se afecta el rendimiento notablemente, eso si que es un problema para mi porque seria muchas consultas a las que le aplicaria la solución, gracias mil...

seguire buscando otra alternativa ...

Kenobi 27-09-2015 20:15:45

buena esa
 
Cita:

Empezado por Casimiro Notevi (Mensaje 497229)
-Señor policía, ¿puede ayudarme?
+Sí, dígame lo que le ocurre.
-No puedo, es secreto.
:confused::confused::confused:
:D

, ojo no es por mezquinar el codigo es simplemente respetar la confidencialidad de la organización ya que mis tablas tienen nombres muy elocuentes....

me disculpo por eso.

AgustinOrtu 27-09-2015 21:38:59

Creo que la mejor forma de independizar del motor es usando interfaces:

Código Delphi [-]
unit SQLFunctions;

interface

uses
  Data.DB;

type
  ISQLFunctions = interface
    ['{CD84579F-2EE3-4842-BCF3-F8B5A2B7C50B}']
    function NullFx(const ParamName, FieldName: string): string;
  end;

  TExtendedSQLConnection = class abstract(TInterfacedObject, ISQLFunctions)
  protected
    FConnection: TCustomConnection;
    function NullFx(const ParamName, FieldName: string): string; virtual; abstract;
  public
    constructor Create(const AConnection: TCustomConnection); virtual;
  end;

implementation

uses
  System.SysUtils;

{ TExtendedSQLConnection }

constructor TExtendedSQLConnection.Create(const AConnection: TCustomConnection);
begin
  if not Assigned(AConnection) then
    raise Exception.Create('TExtendedSQLConnection.Create :: AConnection is not Assigned');

  inherited Create;
  FConnection := AConnection;
end;

end.

Código Delphi [-]
unit MySQLFunctions;

interface

uses
  SQLFunctions;

type
   TMySQLExtendedConnection = class(TExtendedSQLConnection)
   protected
    function NullFx(const ParamName, FieldName: string): string; override;
   end;

implementation

uses
  System.SysUtils;

{ TMySQLExtendedConnection }

function TMySQLExtendedConnection.NullFx(const ParamName, FieldName: string): string;
begin
  Result := Format('IfNull(:%s, %s)', [ParamName, FieldName]);
end;

end.

Código Delphi [-]
unit MSSQLFunctions;

interface

uses
  SQLFunctions;

type
   TMSSQLExtendedConnection = class(TExtendedSQLConnection)
   protected
    function NullFx(const ParamName, FieldName: string): string; override;
   end;

implementation

uses
  System.SysUtils;

{ TMSSQLExtendedConnection }

function TMSSQLExtendedConnection.NullFx(const ParamName, FieldName: string): string;
begin
  Result := Format('IsNull(:%s, %s)', [ParamName, FieldName]);
end;

end.

AgustinOrtu 27-09-2015 21:58:02

Ejemplo de uso:

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
begin
  ADOQuery1.Close;
  if Edit1.Text = EmptyStr then
    ADOQuery1.Parameters.ParamByName('Param').Value := NULL
  else
    ADOQuery1.Parameters.ParamByName('Param').Value := Edit1.Text;
  ADOQuery1.Open;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FSQLFunctions := TMSSQLExtendedConnection.Create(ADOConnection1);
  ADOQuery1.SQL.Text := 'SELECT * FROM Productos WHERE Id = ' + FSQLFunctions.NullFx('Param', 'Id');
  ADOQuery1.Prepared := True;
end;

Edito:

Si las funciones para comprobar si es Null o no comprometen la eficiencia, la unica manera es usando dos componentes Query.

bucanero 28-09-2015 10:48:06

Una alternativa usando solamente parámetros es utilizar dos parámetros, uno que indica que muestre todos y otro para filtrar directamente los datos que queremos

Código SQL [-]
select proyectos, categorias, count(categorias)
from proyectos
where :todos or proyectos=:miParametro
group by proyectos, categorias

y en el codigo de busqueda:

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
begin
  ADOQuery1.Close;
  if Edit1.Text = EmptyStr then
    //se le indica que muestre todos
    ADOQuery1.Parameters.ParamByName('todos').Value := 1
  else begin
    //se obliga a filtra por el dato necesario
    ADOQuery1.Parameters.ParamByName('todos').Value := 0
    ADOQuery1.Parameters.ParamByName('miParametro').Value := Edit1.Text;
  end;
  ADOQuery1.Open;
end;


La franja horaria es GMT +2. Ahora son las 22:56:19.

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