Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Firebird e Interbase (https://www.clubdelphi.com/foros/forumdisplay.php?f=19)
-   -   Parametros en IN del Where (https://www.clubdelphi.com/foros/showthread.php?t=89556)

mRoman 13-12-2015 07:29:41

Parametros en IN del Where
 
Hola amigos buenas noches.

Uso DELPHI6, FireBird 2.0

Estoy tratanto de pasar como parametro una cadena tipo VarChar de 300 en un store procedure. Este el SP estoy construyendo:
Código SQL [-]
CREATE PROCEDURE MOVTOS_MASIVOS_DOTACIONES(
  I_FECHA_INI DATE,
  I_FECHA_FIN DATE,
  I_PORCENTAJE SMALLINT,
  I_LECHERIAS VARCHAR(300))
AS
DECLARE VARIABLE V_NVA_DOT_LTS INTEGER;
DECLARE VARIABLE V_NVA_DOT_CANAST INTEGER;
DECLARE VARIABLE V_LECHERIA NUMERIC(10, 2);
DECLARE VARIABLE V_DOT_ACTUAL_LTS INTEGER;
DECLARE VARIABLE V_DOT_ACTUAL_CANAST INTEGER;
DECLARE VARIABLE V_FECHA_DISTR DATE;
DECLARE VARIABLE V_FECHA_VENTA DATE;
DECLARE VARIABLE V_CANAST_NUEVAS INTEGER;
DECLARE VARIABLE V_LTS_NUEVOS INTEGER;
DECLARE VARIABLE V_CANAST_AFECTADAS INTEGER;
DECLARE VARIABLE V_PIEZAS SMALLINT;
DECLARE VARIABLE V_EQ_LITROS SMALLINT;
BEGIN
     DELETE FROM MOVTOS_MASIVOS_DOTAC;
     FOR SELECT a.FECHA_DISTRIBUCION,
             a.FECHA_VENTA,
            a.lecher,
            a.dotacion_programada,
            ROUND(a.dotacion_programada/(c.piezas*c.equivalente_litros)),
                C.PIEZAS,
                C.EQUIVALENTE_LITROS
       from guia_venta_diaria a,
          lecheria b,
          producto c
         where a.lecher=b.lecher
        and a.fecha_venta between :I_FECHA_INI and :I_FECHA_FIN
        and a.cve_producto=c.cve_producto
        and a.cve_producto like 'AS%'
              and a.LECHER IN (:I_LECHERIAS)
       order by a.fecha_venta,a.lecher
           INTO :V_FECHA_DISTR,
                :V_FECHA_VENTA,
                :V_LECHERIA,
                :V_DOT_ACTUAL_LTS,
                :V_DOT_ACTUAL_CANAST,
                :V_PIEZAS,
                :V_EQ_LITROS DO
                BEGIN
                    V_CANAST_AFECTADAS=round(ROUND(:V_DOT_ACTUAL_LTS/(:V_PIEZAS*:V_EQ_LITROS))*(:I_PORCENTAJE/100.00) );
                    V_CANAST_NUEVAS=:V_DOT_ACTUAL_CANAST-:V_CANAST_AFECTADAS;
                    V_LTS_NUEVOS=:V_CANAST_NUEVAS*(:V_PIEZAS*:V_EQ_LITROS);
                    
                    INSERT INTO MOVTOS_MASIVOS_DOTAC(   FECHA_DISTRIBUCION,
                            FECHA_VENTA,
                            LECHERIA,
                            CVE_PRODUCTO,
                            DOTACION_LTS_ACTUAL,
                            DOTACION_CANASTILLAS_ACTUAL,
                            PORCENTAJE,
                            DOTACION_LTS_NUEVOS,
                            DOTACION_CANASTILLAS_NUEVAS,
                            CANASTILLAS_AFECTADAS)
                                    values(  :V_FECHA_DISTR,
                                             :V_FECHA_VENTA,
                                             :V_LECHERIA,
                                             'AS-606-1315',
                                             :V_DOT_ACTUAL_LTS,
                                             :V_DOT_ACTUAL_CANAST,
                                             :I_PORCENTAJE,
                                             :V_LTS_NUEVOS,
                                             :V_CANAST_NUEVAS,
                                             :V_CANAST_AFECTADAS);

                END
END

Lo marcado en ROJO, se puede usar en un procedimiento almacenado?...o como le hago para se ejecute sin que marque error??

Dentro de Delphi, acumulo ciertos datos del tipo string en una variable, les pongo codigo:
Código Delphi [-]
procedure TfrmMovtosMasivos.BitBtn1Click(Sender: TObject);
var
   i:integer;
begin
    cLecherias:='';
    With lvLecherias do
    begin
         for i:=0 to lvLecherias.Items.Count-1 do
         begin
             if Items[i].Checked then
             begin
                 cLecherias:=cLecherias+Items[i].SubItems[0]+',';
             end;
         end;
    end;
    cLecherias:=copy(cLecherias,1,Length(cLecherias)-1);
    spcDotMasivas.Close;
    spcDotMasivas.ParamByName('i_fecha_ini').AsDate:=FechaInicial.Date;
    spcDotMasivas.ParamByName('i_fecha_fin').AsDate:=FechaFinal.Date;
    spcDotMasivas.ParamByName('i_porcentaje').AsString:=mskPorcentaje.Text;
    spcDotMasivas.ParamByName('i_lecherias').AsString:=cLecherias;
    spcDotMasivas.ExecProc;
end;

Donde en la sección q deje de rojo, intento pasarle una cadena como esta: 12309102,1029301902,109239013, pero marca un error a la hora de ejecutar el SP, el mensaje de error es el siguiente:

Código:

Arithmetic exception, numeric overflow, or string truncation.
At procedure 'MOVTOS_MASIVOS_DOTACIONES'.


Lo anterior es porque quiero pasarle todas las claves en una sola variable al SP, usando el COMANDO IN del WHERE, pero no he podido. Esto claro esta que se puede resolver si quito el FOR del SELECT....bueno quedaria asi:

Código SQL [-]
CREATE PROCEDURE MOVTOS_MASIVOS_DOTACIONES(
  I_FECHA_INI DATE,
  I_FECHA_FIN DATE,
  I_PORCENTAJE SMALLINT,
  I_LECHERIAS NUMERIC(10))
AS
DECLARE VARIABLE V_NVA_DOT_LTS INTEGER;
DECLARE VARIABLE V_NVA_DOT_CANAST INTEGER;
DECLARE VARIABLE V_LECHERIA NUMERIC(10, 2);
DECLARE VARIABLE V_DOT_ACTUAL_LTS INTEGER;
DECLARE VARIABLE V_DOT_ACTUAL_CANAST INTEGER;
DECLARE VARIABLE V_FECHA_DISTR DATE;
DECLARE VARIABLE V_FECHA_VENTA DATE;
DECLARE VARIABLE V_CANAST_NUEVAS INTEGER;
DECLARE VARIABLE V_LTS_NUEVOS INTEGER;
DECLARE VARIABLE V_CANAST_AFECTADAS INTEGER;
DECLARE VARIABLE V_PIEZAS SMALLINT;
DECLARE VARIABLE V_EQ_LITROS SMALLINT;
BEGIN
     DELETE FROM MOVTOS_MASIVOS_DOTAC;
     SELECT a.FECHA_DISTRIBUCION,
             a.FECHA_VENTA,
            a.lecher,
            a.dotacion_programada,
            ROUND(a.dotacion_programada/(c.piezas*c.equivalente_litros)),
                C.PIEZAS,
                C.EQUIVALENTE_LITROS
       from guia_venta_diaria a,
          lecheria b,
          producto c
         where a.lecher=b.lecher
        and a.fecha_venta between :I_FECHA_INI and :I_FECHA_FIN
        and a.cve_producto=c.cve_producto
        and a.cve_producto like 'AS%'
              and a.LECHER=:I_LECHERIAS
       order by a.fecha_venta,a.lecher
           INTO :V_FECHA_DISTR,
                :V_FECHA_VENTA,
                :V_LECHERIA,
                :V_DOT_ACTUAL_LTS,
                :V_DOT_ACTUAL_CANAST,
                :V_PIEZAS,
                :V_EQ_LITROS DO
                BEGIN
                    V_CANAST_AFECTADAS=round(ROUND(:V_DOT_ACTUAL_LTS/(:V_PIEZAS*:V_EQ_LITROS))*(:I_PORCENTAJE/100.00) );
                    V_CANAST_NUEVAS=:V_DOT_ACTUAL_CANAST-:V_CANAST_AFECTADAS;
                    V_LTS_NUEVOS=:V_CANAST_NUEVAS*(:V_PIEZAS*:V_EQ_LITROS);
                    
                    INSERT INTO MOVTOS_MASIVOS_DOTAC(   FECHA_DISTRIBUCION,
                            FECHA_VENTA,
                            LECHERIA,
                            CVE_PRODUCTO,
                            DOTACION_LTS_ACTUAL,
                            DOTACION_CANASTILLAS_ACTUAL,
                            PORCENTAJE,
                            DOTACION_LTS_NUEVOS,
                            DOTACION_CANASTILLAS_NUEVAS,
                            CANASTILLAS_AFECTADAS)
                                    values(  :V_FECHA_DISTR,
                                             :V_FECHA_VENTA,
                                             :V_LECHERIA,
                                             'AS-606-1315',
                                             :V_DOT_ACTUAL_LTS,
                                             :V_DOT_ACTUAL_CANAST,
                                             :I_PORCENTAJE,
                                             :V_LTS_NUEVOS,
                                             :V_CANAST_NUEVAS,
                                             :V_CANAST_AFECTADAS);

                END
END

La pregunta es la siguiente: Puedo hacer esto dentro del WHERE para usar IN, de esta forma:
ej.
where CODIGO IN (:CODIGOS)

Donde CODIGOS, puediera tener la siguientes cadena: 1234,5678,19281 ???

Espero haberme explicado, sino, comentenme para ser mas explicito. Saludos y gracias por su tiempo !.

AgustinOrtu 13-12-2015 16:49:03

Que yo sepa eso no se hace con parametros, en las versiones mas nuevas de de Delphi, con FireDAC incorporado creo que se puede hacer con algo que se llama "macro expand"

Pero en definitiva, lo que termina haciendo es sustituir el lugar indicado dentro del SQL por la secuencia de caracteres. No se como implementarlo dentro de un SP, pero si fuera que mandas un query desde delphi podes hacer algo asi:

Código Delphi [-]
procedure EjecutarSQL;
  procedure BuildStr;
  var
    I: Integer;
  begin
    Result := '';
    for I :=0 to lvLecherias.Items.Count - 1 do
      ...
  end;
begin
  SQL.Text := Format(' WHERE A.Lecher IN (%s) ', [BuildStr]);
  SQL.Open;
  ...
end;

Yo creo que el secreto esta en implementar esa logica dentro del stored, es decir, acumular dentro de una variable local la cadena que se va a usar en el operador IN

mRoman 13-12-2015 18:41:57

Execute Statement
 
Cita:

Empezado por AgustinOrtu (Mensaje 500444)
Que yo sepa eso no se hace con parametros, en las versiones mas nuevas de de Delphi, con FireDAC incorporado creo que se puede hacer con algo que se llama "macro expand"

Pero en definitiva, lo que termina haciendo es sustituir el lugar indicado dentro del SQL por la secuencia de caracteres. No se como implementarlo dentro de un SP, pero si fuera que mandas un query desde delphi podes hacer algo asi:

Código Delphi [-]
procedure EjecutarSQL;
  procedure BuildStr;
  var
    I: Integer;
  begin
    Result := '';
    for I :=0 to lvLecherias.Items.Count - 1 do
      ...
  end;
begin
  SQL.Text := Format(' WHERE A.Lecher IN (%s) ', [BuildStr]);
  SQL.Open;
  ...
end;

Yo creo que el secreto esta en implementar esa logica dentro del stored, es decir, acumular dentro de una variable local la cadena que se va a usar en el operador IN

Antes que nada muchas gracias por contestar y darte tiempo para decirme lo q escribiste.

Efectivamente aplicar una lógica como la q planteas, es lo q busco, y me parece que la solucion esta en esta instruccion:

EXECUTE STATEMENT

Aqui esta un ejemplo. No es otra cosa mas que construir la consulta dentro del SP y concatenar cadenas....y ahi es donde se pudiera hacer lo que busco.

Código SQL [-]
CREATE PROCEDURE MOVTOS_MASIVOS_DOTACIONES(
  I_FECHA_INI DATE,
  I_FECHA_FIN DATE,
  I_PORCENTAJE SMALLINT,
  I_LECHERIAS VARCHAR(300))
AS
DECLARE VARIABLE V_NVA_DOT_LTS INTEGER;
DECLARE VARIABLE V_NVA_DOT_CANAST INTEGER;
DECLARE VARIABLE V_LECHERIA NUMERIC(10, 2);
DECLARE VARIABLE V_DOT_ACTUAL_LTS INTEGER;
DECLARE VARIABLE V_DOT_ACTUAL_CANAST INTEGER;
DECLARE VARIABLE V_FECHA_DISTR DATE;
DECLARE VARIABLE V_FECHA_VENTA DATE;
DECLARE VARIABLE V_CANAST_NUEVAS INTEGER;
DECLARE VARIABLE V_LTS_NUEVOS INTEGER;
DECLARE VARIABLE V_CANAST_AFECTADAS INTEGER;
DECLARE VARIABLE V_PIEZAS SMALLINT;
DECLARE VARIABLE V_EQ_LITROS SMALLINT;
DECLARE VARIABLE V_SENTENCIA VARCHAR(1000);
BEGIN
     DELETE FROM MOVTOS_MASIVOS_DOTAC;
     V_SENTENCIA=' SELECT a.FECHA_DISTRIBUCION,a.FECHA_VENTA,
                  a.lecher,
                  a.dotacion_programada,
                  ROUND(a.dotacion_programada/(c.piezas*c.equivalente_litros)),
                      C.PIEZAS,
                      C.EQUIVALENTE_LITROS
             from guia_venta_diaria a,
               lecheria b,
               producto c
              where a.lecher=b.lecher
              and a.fecha_venta between '''||I_FECHA_INI||''' and '''||I_FECHA_FIN||'''
              and a.cve_producto=c.cve_producto
              and a.cve_producto like ''AS-606-1315''
                    and a.LECHER IN ('||I_LECHERIAS||') 
                    order by a.fecha_venta,a.lecher';
     FOR EXECUTE STATEMENT V_SENTENCIA
           INTO :V_FECHA_DISTR,
                :V_FECHA_VENTA,
                :V_LECHERIA,
                :V_DOT_ACTUAL_LTS,
                :V_DOT_ACTUAL_CANAST,
                :V_PIEZAS,
                :V_EQ_LITROS DO
                BEGIN
                    V_CANAST_AFECTADAS=round(ROUND(:V_DOT_ACTUAL_LTS/(:V_PIEZAS*:V_EQ_LITROS))*(:I_PORCENTAJE/100.00) );
                    V_CANAST_NUEVAS=:V_DOT_ACTUAL_CANAST-:V_CANAST_AFECTADAS;
                    V_LTS_NUEVOS=:V_CANAST_NUEVAS*(:V_PIEZAS*:V_EQ_LITROS);
                    
                    INSERT INTO MOVTOS_MASIVOS_DOTAC(   FECHA_DISTRIBUCION,
                            FECHA_VENTA,
                            LECHERIA,
                            CVE_PRODUCTO,
                            DOTACION_LTS_ACTUAL,
                            DOTACION_CANASTILLAS_ACTUAL,
                            PORCENTAJE,
                            DOTACION_LTS_NUEVOS,
                            DOTACION_CANASTILLAS_NUEVAS,
                            CANASTILLAS_AFECTADAS)
                                    values(  :V_FECHA_DISTR,
                                             :V_FECHA_VENTA,
                                             :V_LECHERIA,
                                             'AS-606-1315',
                                             :V_DOT_ACTUAL_LTS,
                                             :V_DOT_ACTUAL_CANAST,
                                             :I_PORCENTAJE,
                                             :V_LTS_NUEVOS,
                                             :V_CANAST_NUEVAS,
                                             :V_CANAST_AFECTADAS);

                END
END^

Pero me marca error al momento de ejecutarlo:
Código:

Variable type (position 6) in EXECUTE STATEMENT 'SELECT a.FECHA_DISTRIBUCION,
 ' INTO does not match returned column type.
At procedure 'MOVTOS_MASIVOS_DOTACIONES'.


ecfisa 14-12-2015 01:13:24

Hola mRoman.
Cita:

Empezado por mRoman (Mensaje 500440)
Hola amigos buenas noches.

Uso DELPHI6, FireBird 2.0

Estoy tratanto de pasar como parametro una cadena tipo VarChar de 300 en un store procedure. Este el SP estoy construyendo:
Código SQL [-]
...
              and a.LECHER IN (:I_LECHERIAS)
...

La pregunta es la siguiente: Puedo hacer esto dentro del WHERE para usar IN, de esta forma:
ej.
where CODIGO IN (:CODIGOS)

Donde CODIGOS, puediera tener la siguientes cadena: 1234,5678,19281 ???
...

Si interpreté bién tu problema, y estuvieras usando la versión Firebird 2.1, te sugeriría usar la función POSITION, la que podrías usar como en el ejemplo siguiente:
Código SQL [-]
SELECT *
FROM LA_TABLA
WHERE ... 
  AND (POSITION(EL_CAMPO IN :PARAMETRO) <> 0)
Pero lamentablemente en la versión 2.0 aún no está implementada.

De todos modos podes hacerte tu versión de la funcion como expongo en el mensaje #9 de este enlace: Buscar Valor dentro de una Cadena.

Y en ese caso podrías hacer:
Código SQL [-]
SELECT *
FROM LA_TABLA
WHERE ... 
  AND ((SELECT RESULT FROM POS(EL_CAMPO, :PARAMETRO)) <> 0)

Saludos :)

mRoman 16-12-2015 06:03:00

Aplicare
 
Buenas noches.

Gracias ecfisa por contestar y por tu tiempo, haré una prueba con lo que me indicas y les comento como me fue

Saludos

fjcg02 16-12-2015 09:46:50

Hola,
en la procedure que pones, veo que puedes rener un error.

Intenta que la procedure te devuelva el texto de la select que ejecutas en el execute estatement. Luego la intentas ejecutar. Así podrás descubrir qué falla.

Por lo que observo, tienes
Código SQL [-]
and a.LECHER IN ('||I_LECHERIAS||')
tras sustituir por el valor quedaría
Código SQL [-]
and a.LECHER IN ('Lecheria01,lecheria02,Lecheria03')

Esto estaría mal. Lo correcto sería
Código SQL [-]
and a.LECHER IN ('Lecheria01','lecheria02','Lecheria03')

Al menos es lo que a mi me parece.

Un saludo

mRoman 16-12-2015 21:55:13

Gracias
 
Cita:

Empezado por fjcg02 (Mensaje 500593)
Hola,
en la procedure que pones, veo que puedes rener un error.

Intenta que la procedure te devuelva el texto de la select que ejecutas en el execute estatement. Luego la intentas ejecutar. Así podrás descubrir qué falla.

Por lo que observo, tienes
Código SQL [-]
and a.LECHER IN ('||I_LECHERIAS||')
tras sustituir por el valor quedaría
Código SQL [-]
and a.LECHER IN ('Lecheria01,lecheria02,Lecheria03')

Esto estaría mal. Lo correcto sería
Código SQL [-]
and a.LECHER IN ('Lecheria01','lecheria02','Lecheria03')

Al menos es lo que a mi me parece.

Un saludo

Gracias fjcg02 por contestar. Fijate que no he probado eso....efectivamente estoy pasando sin comillas simples el parámetro al store procedure, veré si esto esta afectando. En otra prueba que hice, realice esto:

Código SQL [-]
and a.LECHER IN (||I_LECHERIAS||)

Pero también marco error....bueno algo, pero sigo probando. Ahora haré una prueba con lo q me comentas.

Nuevamente les agradezco su interes en ayudarme. Saludos.

fjcg02 16-12-2015 22:19:58

Hola,

hacer
Código SQL [-]
and a.LECHER IN (||I_LECHERIAS||)

valdría si pones las comillas o en el parámetro o en la construcción de la cadena. La sustitución del parámetro generaría la cadena
Código SQL [-]
and a.LECHER IN (Lecheria01)
Estoy suponiendo que tu parámetro contiene "Lecheria01".

cuando debería ser
Código SQL [-]
and a.LECHER IN ('Lecheria01')

Por eso te digo que hagas que la función devuelva la select. Luego la recoges y la ejecutas en donde ejecutes las querys a pelo ( el ibexpprt o similar). Si funcionan, es que se generan correctamente.

Saludos


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

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