Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Oracle (https://www.clubdelphi.com/foros/forumdisplay.php?f=22)
-   -   Conocer el nº de filas devueltas en una consulta (https://www.clubdelphi.com/foros/showthread.php?t=15498)

Jose Manuel 25-10-2004 22:06:36

Conocer el nº de filas devueltas en una consulta
 
Hola, estoy trabajando con D6 y empiezo con Oracle 9i + componentes ODAC. Mi pregunta es como conseguir que al realizar una consulta, si el nº de filas devueltas es muy grande, aparezca un mensaje informativo y si es posible, pregunte si deseamos continuar o no, con la consulta.

Por ejemplo, cuando hago la siguiente consulta, desconozco el nº de filas que me devolverá la consulta, por lo que me gustaría poder saber a priori que si el nº de filas devueltas supera, por ejemplo las 100 , entonces aparezca un mensaje de aviso dando la opción de continuar o limitar el rango de la consulta.

Un saludo
Jose Manuel


Código:


procedure TfDNI.Btn_fechasClick(Sender: TObject);
begin
  fdm.tbNif.close;
  fdm.tbNif.SQL.Clear;
  fdm.tbNif.SQL.Text := 'SELECT * FROM &tablename1 '        +#13+
                        'WHERE (F_ULTIMO_CONTACTO >= :desde' +#13+
                        'and      F_ULTIMO_CONTACTO <= :hasta)' +#13+
                        'ORDER BY A_nombre';
  fdm.tbNif.MacroByName('TableName1').Value := cb_tablespace.Text;
  fdm.tbNif.ParamByName('desde').AsDateTime := desde.date;
  fdm.tbNif.ParamByName('hasta').AsDateTime := hasta.date;
  fdm.tbNif.Open;
end;


roman 25-10-2004 22:13:31

Pues de Oracle no tengo ni idea pero ¿por qué no sustituyes select * por select count(*) en tu consulta? De esta forma sabrás el número de registros que te devolverá la consulta original.

// Saludos

Jose Manuel 25-10-2004 22:43:35

Gracias por responder, pero dime una cosa, con esta instrucción el nº de filas lo coneceré una vez está la consulta en la pantalla, y yo lo que pretendo, es que teniendo un grid, la consulta que pueda hacer un cliente no sea tan grande que colapse la red, por ejemplo que ¿pasaría si la consulta devuelve 50000 registros?

Bueno, probaré esta instrucción a ver si me ayuda con esto.

Gracías y un saludo.
Jose Manuel

roman 25-10-2004 22:53:34

Cita:

Empezado por Jose Manuel
pero dime una cosa, con esta instrucción el nº de filas lo coneceré una vez está la consulta en la pantalla

No. Con esa consulta (select count) no traes ningún registro, únicamente obtienes el número de registros que satisfacen las condiciones. Este tipo de consultas suele ser muy rápido de manera que no pierdes gran cosa. Si el número de filas no es muy alto entonces sí mandas llamar tu consulta original para traer los registros y en caso contrario mandas el aviso al usuario.

// Saludos

Neftali [Germán.Estévez] 26-10-2004 10:46:05

Cita:

Empezado por roman
¿por qué no sustituyes select * por select count(*) en tu consulta?

Aun mejor si utilizas para el Count el campo de clave primaria, es decir Select Count(CampoPK)... (el resto de la consulta igual que estaba)

Cita:

Empezado por Jose Manuel
la consulta que pueda hacer un cliente no sea tan grande que colapse la red, por ejemplo que ¿pasaría si la consulta devuelve 50000 registros?

Has pensado en utilizar Filtros previos o TOP;
Personalmente considero que hacer (o que el usuario haga) una consulta que devuelve 50000 registros es inútil; y lo subrayo porque además de inútil lo considero un "error" de programación; Resulta que el usuario hace una consulta (en un Grid por ejemplo) que devueve 50000 registros y el registro que le interesa está en la posición 14356, ¿realmente lo va a encontrar? ¿Realmente lo va a buscar? porque no me imagino un usuario dándole al cursor o a la barra de desplazamiento hasta esa posición.

Creo que en éstos casos se debería sacar un filtro previo para que el usuario seleccione determinados valores y utilizar un TOP (yo utilizao ambas cosas, al igual que SAP, por ejemplo); El top por defecto son 500 (aunque el usuario puede modificarlo);

NOTA: Normalmente en un tabla grande suele ser más rápido un TOP 200 que un Count (ya que el count, aunque sólo sea para contar debe recorrer toda la tabla...)

Cita:

Empezado por Jose Manuel
¿que pasaría si la consulta devuelve 50000 registros?

(si al final y después de todo llegas a esa situación...)
Para esos casos debes configurar la conexión como Cliente-Servidor; ADO, IBExpress,... poseen alguna propiedad en la conexión que te permite configurar ésta modalidad de forma que en una consulta de 50000 registros se "traen" por bloques, primero se traen 250 y a medida que el usuario pide más (baja en el Grid, por ejemplo) se van trayendo el resto.

De todas formas mi consejo es que evites a todas costa llegar a esa situación (ejecutar ésta un select con un resultado de 50000 registros).

roman 26-10-2004 15:16:17

Cita:

Empezado por Neftali
De todas formas mi consejo es que evites a todas costa llegar a esa situación (ejecutar ésta un select con un resultado de 50000 registros).

Creo que esto es precisamente lo que Jose Manuel quiere evitar y por ello está preguntando.

Su enfoque me parece adecuado. Si el usuario hace una búsqueda que va a devolver una cantidad más allá de un límite razonable de registros, ¿qué mejor que avisarle para que refine su búsqueda antes de lanzar la consulta real que traiga los registros?

// Saludos

Jose Manuel 26-10-2004 22:42:05

Hola, he probado a sustituir la instrucción
'SELECT * FROM &tablename1 WHERE ' por
'SELECT count(*) FROM &tablename1 WHERE '
y me da un error, indicando que el campo C_NIF no se encuentra, aunque existe y es el primer campo de la tabla, y forma parte de la clave única de la tabla CONSTRAINT "TA_NIF_C_NIF_C_VERSION_PK" UNIQUE("C_NIF", "N_VERSION")

No sé, tal vez hay algún error en la sintesis - trabajo con Oracle 9i + Odac + D6-, de momento estoy intentando encontrar algún ejemplo que incluya esta instrucción, mientras tanto he modificado el codigo de la siguiente manera, aunque no lo veo muy claro:

Un saludo a todos
Jose Manuel García


Código:

procedure TfDNI.Btn_consulta_fechasClick(Sender: TObject);
var
n,ini,fin,y:Double;
i,x:integer;
begin
  // deberia comprobar el nº de filas devueltas en la consulta
  fdm.tbNif.close;
  fdm.tbNif.SQL.Clear;
  fdm.tbNif.SQL.Text := 'SELECT COUNT(*) FROM &tablename1 WHERE '+#13+
                        '(F_ULTIMO_CONTACTO >= :desde'+#13+
                        ' and F_ULTIMO_CONTACTO <= :hasta)'+#13+
                        'ORDER BY A_nombre';
  fdm.tbNif.MacroByName('TableName1').Value := cb_tablespace.Text;
  fdm.tbNif.ParamByName('desde').AsDateTime := desde.date;
  fdm.tbNif.ParamByName('hasta').AsDateTime := hasta.date;
  if desde.date=hasta.date then hasta.date  := desde.date+1;
  fdm.tbNif.Open;

  n:=fdm.tbNif.Recordcount; // nº de filas de la tabla
  ShowMessage ('Nº de filas devueltas = '+FormatFloat('####',n)); // esto se debe quitar

  // si el nº de filas devueltas es > 100, sugerir limitar el ambito de la consulta
  if n>10 then
      begin
      text:='Esta consulta tiene '+FormatFloat('####',n)+' filas'+#13+
            'le recomendamos, limite el ámbito de la consulta'+#13+#13+
            'Pulse Cancelar para salir';

      IF Application.MessageBox((pChar(text)) ,'CONSULTAS ',
        mb_OkCancel + mb_IconExclamation)=IdCancel then Exit;

      end;

    // si no se limita el ambito y el nº de filas devueltas es > 10 (el nº de puede aumentar)
    // se muestra el resultado de 10 en 10, dando opción a cancelar la consulta
    if n>10 then
        begin
        y:=(int(n/10))+1;
        i:=StrToint(FloatToStr(y));
        for x:=1 to i do
            begin
            ini:=x-1*10;  // se puede cambiar para mostrar bloques de más de  10 filas
            fin:=x*10;
            fdm.tbNif.close;
            fdm.tbNif.SQL.Clear;
            fdm.tbNif.SQL.Text := 'SELECT * FROM &tablename1 WHERE '+#13+
                                  '    (F_ULTIMO_CONTACTO >= :desde'+#13+
                                  ' and F_ULTIMO_CONTACTO <= :hasta)'+#13+
                                  ' and(rownum > :ini'  +#13+
                                  ' and rownum <= :fin)'+#13+
                                  'ORDER BY A_nombre';
            fdm.tbNif.MacroByName('TableName1').Value := cb_tablespace.Text;
            fdm.tbNif.ParamByName('desde').AsDateTime := desde.date;
            fdm.tbNif.ParamByName('hasta').AsDateTime := hasta.date;
            fdm.tbNif.ParamByName('ini').AsFloat := ini;
            fdm.tbNif.ParamByName('fin').AsFloat := fin;
            if desde.date=hasta.date then hasta.date  := desde.date+1;
            fdm.tbNif.Open;

            text:='Quieres ver los siguientes 10 registros'+#13+
                  'Pulse Cancelar para salir';

            IF Application.MessageBox((pChar(text)) ,'CONSULTA ',
              mb_OkCancel + mb_IconExclamation)=IdCancel then Exit;
            end;
        end
        else
        begin
        fdm.tbNif.close;
        fdm.tbNif.SQL.Clear;
        fdm.tbNif.SQL.Text := 'SELECT * FROM &tablename1 WHERE '+#13+
                              '    (F_ULTIMO_CONTACTO >= :desde'+#13+
                              ' and F_ULTIMO_CONTACTO <= :hasta)'+#13+
                              'ORDER BY A_nombre';
        fdm.tbNif.MacroByName('TableName1').Value := cb_tablespace.Text;
        fdm.tbNif.ParamByName('desde').AsDateTime := desde.date;
        fdm.tbNif.ParamByName('hasta').AsDateTime := hasta.date;
        if desde.date=hasta.date then hasta.date  := desde.date+1;
        fdm.tbNif.Open;
      end;
end;


roman 26-10-2004 22:53:16

Como te dije, yo no conozco Oracle. Pero la consulta que haces se ve bastante estándar así como lo es el count. Ahora, en el error que te marca se menciona el campo C_NIF que no aparece en ninguna parte de la consulta- ni la original, ni la que usa count. Quizá la componente tbNif la tengas asociada a algún DBGrid u otro control db que hacía referencia a dicho campo. Al sustituir * por count(*) tal campo ya no aparece en los resultados de la consulta. Si es algo por el estilo intenta entonces usar otra componente para obtener el número de registros (consulta count).

// Saludos

roman 26-10-2004 22:58:27

Para que quede un poco más claro

Una consulta de la forma:

Código SQL [-]
select count(*) from tabla
where
  condiciones

te regresa un sólo registro con una sóla celda que contiene el número de registros de la tabla que satisfacen las condiciones.

La consulta

Código SQL [-]
select * from tabla
where
  condiciones
te devuelve todos los registros de la tabla que satisfacen las condiciones.

La primera consulta es muy rápida ya que el conteo lo hace el servidor mandando al cliente únicamente una celda.

// Saludos

Neftali [Germán.Estévez] 27-10-2004 09:49:05

Cita:

Empezado por Jose Manuel
Hola, he probado a sustituir la instrucción
'SELECT * FROM &tablename1 WHERE ' por
'SELECT count(*) FROM &tablename1 WHERE '
y me da un error, indicando que el campo C_NIF no se encuentra

Yo utilizaría un Query diferente para realizar la consulta del Count
Código SQL [-]
SELECT COUNT(*) AS NUMREG FROM...

No utilices el mismo que usas para la consulta de datos y para acceder al resultado hazlo utilizando FieldByName.

Código Delphi [-]
  n := Qrery2.FieldByName('NUMREG').AsInteger;

Otra cosa, es que puedes eliminar de la consulta del Count el ORDER BY ya que es indiferente para el número de registros.

Jose Manuel 28-10-2004 13:52:29

nº de filas devueltas en una consulta
 
Hola, he descubierto que el componente ODAC que estoy utilizando para la conexión a ORACLE, tiene una opción que soluciona el problema que origino esta consulta, al tener la posibilidad de indicar que no traiga de una sola vez todas las filas de la consulta, y de indicar el nº de filas que debe traer en cada bloque.

TOraQuery.fetchAll :=False
TOraQuery.fetchRows :=25


En las propiedades del componente he puesto estos datos, y ahora en el caso de una consulta que devuelva 1000 registros, primero trae 25 y solo si llego con el cursor al registro 25, automaticamente se obtiene un segundo bloque de 25 registros, y así hasta el final si continuamos la consulta.

Un saludo a todos y gracias por vuestros comentarios.
Jose Manuel


La franja horaria es GMT +2. Ahora son las 05:47:31.

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