Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Contar la cantidad de registros de un dbgrid (https://www.clubdelphi.com/foros/showthread.php?t=87287)

dany2014 08-12-2014 21:23:16

Contar la cantidad de registros de un dbgrid
 
Hola foristas, soy nuevo en esto del mundo delphi, y necesitaria hacer una consulta. Tengo un dbgrid con los campos de una tabla alumnos, donde tengo los campos idAlum, Año de curso, Materia, y la Nota, lo que deseo es poder contar la cantidad de registros del dbgrid asociado a esa tabla y poder almacenarlo esa cantidad en un dbedit, que esta en el mismo formulario donde se encuentra el dbgrid, y almacenarlo en otra tabla, ya que ese dbedit esta apuntado a una tabla detalle de alumno, donde se almacenara la cantidad de registros del dbgrid. Desde ya gracias por la informacion que me puedan aportar. Saludos

edgargh 09-12-2014 00:36:18

que tal dany2014, bienvenido al foro, si lo que necesitas es obtener el numero de registros de tu dbgrid, lo mas comun es hacerlo directamente a traves del dataset asociado (query o table).

ejemplo:

Cita:

Query1.RecordCount;
o si te parece mejor asi:

Cita:

DBGrid1.DataSource.DataSet.RecordCount;
De cualquiera de las 2 maneras obtienes el numero de registros de tu dbgrid y puedes visualizarlo en un edit en lugar de un dbedit.

Por otro lado, no entiendo para que necesitas guardar ese dato en la base de datos, no le veo sentido, ni en la tabla alumnos, mucho menos en la tabla detalle de alumnos.

Casimiro Notevi 09-12-2014 10:11:44

Con query.recordcount no funcionará, solamente devolverá el dato correcto si ha posicionado en el último registro, ejemplo query.last

edgargh 09-12-2014 20:15:31

Casimiro, claro que funciona, lo he hecho infinidad de veces y ha funcionado, lo he vuelto a hacer (por aquello de que nadie tiene la verdad absoluta) y hace lo que pregunta dany2014 ("lo que deseo es poder contar la cantidad de registros del dbgrid asociado a esa tabla").

Casimiro Notevi 09-12-2014 20:20:25

No :)

Primero hay que aclarar qué base de datos se está usando. Pero en general, cuando ejecutas un query de consulta, recordcount, no sabe cuántos registros has traído, salvo que vayas al último.
Algunas bases de datos te devuelven la cantidad de registros.

edgargh 09-12-2014 20:44:09

¿El funcionamiento de la propiedad recordcount de un TDataset en delphi depende del manejador de base de datos que se utilize?, no lo sabia, yo trabajo con sql server y funciona, ignoraba que con otros no. ¿Con que manejador de base de datos no funciona la propiedad recordcount de un Tdataset?

Casimiro Notevi 09-12-2014 20:49:14

O sea, tú ejecutas un query, por ejemplo:
Código Delphi [-]
q.close;
q.sql.text = 'select codigo, nombre from tbClientes where provincia=28';
q.execquery;
showmessage(q.recordcount,"");
¿Eso muestra los registros que ha traido el query?

edgargh 09-12-2014 21:15:37

Casimiro, por el uso de la propiedad execquery de tu ejemplo entiendo que utilizas un TIBSQL que se enfoca especificamente a Interbase, no es la manera estandar de trabajar con datasets en delphi, creo que ese es tu problema. Un TDataset no esta limitado a trabajar con un solo manejador de base de datos como interbase. por ejemplo si trabajas con Tdatasets de ADO o DBExpress, que segun yo son los mas comunes y en los cuales puedes hacer la conexion con una infinidad de manejadores de bases de datos (incluyendo interbase), no tendrias el problema que mencionas

Casimiro Notevi 09-12-2014 22:41:13

Cita:

Empezado por edgargh (Mensaje 486375)
Casimiro, por el uso de la propiedad execquery de tu ejemplo entiendo que utilizas un TIBSQL que se enfoca especificamente a Interbase, no es la manera estandar de trabajar con datasets en delphi, creo que ese es tu problema. Un TDataset no esta limitado a trabajar con un solo manejador de base de datos como interbase. por ejemplo si trabajas con Tdatasets de ADO o DBExpress, que segun yo son los mas comunes y en los cuales puedes hacer la conexion con una infinidad de manejadores de bases de datos (incluyendo interbase), no tendrias el problema que mencionas

Bueno, mejor dicho que no es tu forma de trabajar ;)
Y en cuanto a lo estandar, lo mismo digo :)
Y además, yo no tengo ningún problema :D

edgargh 09-12-2014 23:47:30

jaja, donde estas Neftali?, ayuda a este pobre hombre.

Casimiro Notevi 10-12-2014 10:48:42

A ver, edgargh, un select a una base de datos devuelve una serie de registros, ¿cuántos?, no se puede saber. ¿Por qué el componente que estás usando, y otros también, pueden saberlo?, pues porque han añadido un contador. Pues la única manera de saber cuántos registros hay en una consulta es contarlos, para eso la única forma es hacer un fetch, o sea, ir al último.
Algunos añadidos en algunas bases de datos y componentes, han incorporado código para que cuando se están pasando los registros que ha devuelto la consulta, los vaya contando. Hay diversas maneras, tampoco voy a escribir un tratado de cómo se hace, pero no es lo normal.

orodriguezca 10-12-2014 16:18:05

Casimiro tiene razón. Independiente del tipo de dataset con el que se haga la consulta, a menos que haga Fetch a todos los registros no hay forma de saber cuantos registros retornará la consulta.

Ahora, muchas veces los grids y algunos dataset, para mejorar el rendimiento, suelen recuperar la mayor cantidad posible de filas (en el caso del CXGrid todas las filas) para tenerlas disponibles tan pronto se ejecuta el Open de la consulta. En la mayoría de las ocasiones esto trae como consecuencia que "accidentalmente" todas las filas de la consulta son leídas por el cliente y el dato que obtenemos con Query1.RecordCount es correcto, pero la única forma de saber cuantas filas regresó nuestra consulta es leyéndolas todas, ya sea realizando un Query1.FetchAll o un Query1.Last.

Casimiro Notevi 10-12-2014 16:31:36

Cita:

Empezado por orodriguezca (Mensaje 486403)
..

Exactamente ^\||/
Aunque no se hace por mejorar el rendimiento, ya que es justo lo contrario, esa forma es lo menos eficiente que existe para traerse datos de una consulta.
Se hace para "facilitar" el uso al usuario, como dices, los componentes que mencionas se trae todos, por defecto, para poder luego hacer filtros y cosas con ellos.
Evidentemente no es la forma correcta de trabajar, y mucho menos para trabajar por internet, ya que se trae todos los registros... ¿y si tienes millones de registros?, o sea, es un despropósito en cuanto a rendimiento.

ElDioni 10-12-2014 16:50:31

Hola,

yo trabajo con Access y también me devuelve el número total de registros sin tener que ir al último o hacer un fetch, simplemente con

Código Delphi [-]
adoquery1.close;
adoquery1.sql.text:='SELECT * FROM clientes';
adoquery1.open;
showmessage(inttostr(adoquery1.recordcount));

me sale el número total de registros que hay en la consulta realizada.

como no he trabajado con otras bases de datos para mi esto también es lo normal.

Saludos.

Casimiro Notevi 10-12-2014 16:55:23

Pues a lo que he comentado antes, ahora hay que añadir que access no es una base de datos relacional, es una base de datos de escritorio, como los dbf de otra época.

orodriguezca 10-12-2014 16:55:35

De Acuerdo casimiro, traer todos los registros de un solo golpe cuando son millones es un total despropósito. Es por esto que cuando se diseñan las consultas se deben acotar lo suficiente para no abrumar con tanta data a el pobre usuario: un millón de registros en la pantalla no sirven para nada.

Por otra parte, la mayoría de las veces, las consultas que realiza una aplicación bien pensada, para interactuar con datos en la pantalla, devuelve un número pequeño de registros, digamos menos de 100 registros. En estos casos, y dependiendo de los drivers y de la base de datos, leer todos los registros en una única operación puede mejorar significativamente el performance al "agrupar" la lectura de varios registros en una sola operación I/O. Por supuesto, esto no siempre aplica y por ello cada escenario que se nos presenta deber ser considerado de forma individual.

orodriguezca 10-12-2014 17:02:54

Cita:

Empezado por ElDioni (Mensaje 486407)
Hola,

yo trabajo con Access y también me devuelve el número total de registros sin tener que ir al último o hacer un fetch, ...

En estos casos, cuando es una base de datos de escritorio, le toca a ADO o al BDE hacer el papel de Motor de Bases de Datos y por tanto sabe cuantos registros está manipulando/consultando.

edgargh 10-12-2014 17:24:02

Cita:

Empezado por orodriguezca (Mensaje 486403)
Casimiro tiene razón. Independiente del tipo de dataset con el que se haga la consulta, a menos que haga Fetch a todos los registros no hay forma de saber cuantos registros retornará la consulta.

Ahora, muchas veces los grids y algunos dataset, para mejorar el rendimiento, suelen recuperar la mayor cantidad posible de filas (en el caso del CXGrid todas las filas) para tenerlas disponibles tan pronto se ejecuta el Open de la consulta. En la mayoría de las ocasiones esto trae como consecuencia que "accidentalmente" todas las filas de la consulta son leídas por el cliente y el dato que obtenemos con Query1.RecordCount es correcto, pero la única forma de saber cuantas filas regresó nuestra consulta es leyéndolas todas, ya sea realizando un Query1.FetchAll o un Query1.Last.


Te consta lo que dices?, lo haz hecho con un adoquery por ejemplo?, no te ha funcionado el recordcount?

edgargh 10-12-2014 17:35:02

Cita:

Empezado por Casimiro Notevi (Mensaje 486395)
A ver, edgargh, un select a una base de datos devuelve una serie de registros, ¿cuántos?, no se puede saber. ¿Por qué el componente que estás usando, y otros también, pueden saberlo?, pues porque han añadido un contador. Pues la única manera de saber cuántos registros hay en una consulta es contarlos, para eso la única forma es hacer un fetch, o sea, ir al último.
Algunos añadidos en algunas bases de datos y componentes, han incorporado código para que cuando se están pasando los registros que ha devuelto la consulta, los vaya contando. Hay diversas maneras, tampoco voy a escribir un tratado de cómo se hace, pero no es lo normal.


Lo único que te puedo decir porque lo he hecho infinidad de veces y puedo demostrarlo con un ejemplo sencillo si gustas, es que si yo tengo un adoquery por ejemplo, puedo obtener el total de registros a través de la propiedad recordcount. No es algo que este inventando yo (No tengo tanta capacidad) esa es la función de esa propiedad. Desde mi punto de vista la propiedad last se utiliza para ir al ultimo registro no para obtener el total de registros, para eso es la propiedad recordcount de un tdataset y no tiene nada que ver con el manejador de base de datos.

Entiendo la parte de que cada quien puede hacerlo a su manera, pero no estoy de acuerdo que se diga que no funciona algo que me consta que si. Saludos

orodriguezca 10-12-2014 17:57:06

edgargh tienes y no tienes razón. Te explico porque:

Cuando se crea un objeto de la clase TADOQuery por defecto la propiedad CursorLocation se establece a clUseClient. En esta modalidad ADO se comporta en forma "desconectada" y transfiere todas (absolutamente todas) las filas de la consulta al lado del cliente aunque no se haya hecho un FetchAll o un Last. Es por esto que funciona el RecordCount, porque ADO transfiere todas las filas al cliente y las va contando a medida que las va transfiriendo. Si la propiedad CursorLocation se establece a clUseServer las filas solo se transferirán al cliente bajo demanda, ya sea navegando en un Grid o haciendo uso de los métodos Next, Last o FetchAll.

Espero quede aclarado.

Casimiro Notevi 10-12-2014 18:01:08

Desconozco cómo trabajan los componentes ADO que estás usando.
E insisto en que un query de consulta a una tabla no devuelve el número de registros que cumplen la condición, salvo que vayas al último.

edgargh 10-12-2014 18:30:19

totalmente de acuerdo orodriguezca, pero ya estas hablando del funcionamiento interno de un componente para poder lograr hacer algo, eso no es lo que pregunto dany2014, el solo quiere saber como "Contar la cantidad de registros de un dbgrid", la respuesta es con la propiedad recordcount del tdataset, asi de sencillo. Que internamente el componente haga x ó y cosas para llegar al resultado que se obtiene de llamar a la propiedad recordcount debe ser transparente para el usuario, eso no le interesa. Imaginate que para cada pregunta que hagan los foristas adicional a decirles con que propiedades o métodos pueden lograrlo, tengas que explicar como funciona internamente cada una de esas propiedades o métodos, no creo que eso sea necesario.

Pero en fin, creo que ya se ha desvirtuado el origen de todo esto que fue la pregunta inicial de dany2014, espero no lo hayamos confundido con todo esto, de mi parte estoy a sus ordenes por si necesita que se le facilite un ejemplo de lo que quiere hacer si es que se le complica. Saludos

Casimiro Notevi 10-12-2014 18:33:53

Es que tampoco estás respondiendo correctamente a dany2014 porque no sabes qué componentes está usando, ni qué base de datos, ni nada.

orodriguezca 10-12-2014 19:26:47

Independiente de cual es la base de datos o del tipo de dataset lo correcto para determinar el número de registro es hacer:

Código Delphi [-]
  MyDataset.FetchAll;
  NumeroDeRegistros := MyDataset.RecordCount;


Cita:

Te consta lo que dices?, lo haz hecho con un adoquery por ejemplo?, no te ha funcionado el recordcount?
Si, me consta.

- Trabajando con ADO, ya sea en Delphi o Visual Basic 6, y configurando los cursores del lado del servidor, RecordCount devuelve cero y la consulta puede regresar 5 0 10 millones de registros. En estos casos si se deja que los cursores queden del lado del cliente la aplicación "estalla" por falta de memoria. Estos registros no se muestran ni se imprimen, simplemente se consolida información del Sistema de Producción en el Sistema Contable

- Trabajando con DBExpress: TSQLQuery.RecordCount devuelve un valor erróneo. En este caso es necesario llegar hasta el último registro para saber cuantos son.

- Con los componentes Interbase.

Casimiro Notevi 10-12-2014 19:44:46

La forma correcta y segura de obtener los registros es contarlos:
Código SQL [-]
select count(id) from tabla where campo = loquesea

edgargh 10-12-2014 20:53:31

Cita:

Empezado por orodriguezca (Mensaje 486425)
Independiente de cual es la base de datos o del tipo de dataset lo correcto para determinar el número de registro es hacer:

Código Delphi [-]
  MyDataset.FetchAll;
  NumeroDeRegistros := MyDataset.RecordCount;




Si, me consta.

- Trabajando con ADO, ya sea en Delphi o Visual Basic 6, y configurando los cursores del lado del servidor, RecordCount devuelve cero y la consulta puede regresar 5 0 10 millones de registros. En estos casos si se deja que los cursores queden del lado del cliente la aplicación "estalla" por falta de memoria. Estos registros no se muestran ni se imprimen, simplemente se consolida información del Sistema de Producción en el Sistema Contable

- Trabajando con DBExpress: TSQLQuery.RecordCount devuelve un valor erróneo. En este caso es necesario llegar hasta el último registro para saber cuantos son.

- Con los componentes Interbase.

pasame el ejemplo donde te consta que usando el adoquery no funciona el recordcount

orodriguezca 10-12-2014 21:42:12

Aquí no funciona correctamente RecordCount
 
Código Delphi [-]
program Project10;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  adodb,
  db,
  ActiveX;

var
  Conn: TAdoConnection;
  AdoQuery1: TAdoQuery;
begin
  CoInitialize(nil);
  try
    Conn := TAdoConnection.Create(nil);
    try
      conn.ConnectionString :=
        'Provider=SQLNCLI10.1;' +
        'Integrated Security=SSPI;' +
        'Persist Security Info=False;' +
        'User ID="";' +
        'Initial Catalog=SELA;' +
        'Data Source=MyDireccionIP;' +
        'Initial File Name="";' +
        'Server SPN=""';
      conn.Open();

      AdoQuery1 := TAdoQuery.Create(nil);
      try
        AdoQuery1.Connection := Conn;
        AdoQuery1.CursorLocation := clUseServer;
        AdoQuery1.CursorType := ctOpenForwardOnly;

        AdoQuery1.SQL.Text := 'select * from PARAMETROS';
        AdoQuery1.Open;
        WriteLn('Numero de registros: ', AdoQuery1.RecordCount);
        //AdoQuery1.RecordCount restorna -1 en SQL Server.
        // en DB2 for i retorna 0
        AdoQuery1.Close;
      finally
        AdoQuery1.Free;
      end;

    finally
      Conn.Free;
    end;
    ReadLn;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

edgargh 11-12-2014 03:09:07

ok, gracias por el ejemplo, ya me queda claro de donde vienen las discrepancias entre los 2 en eso del recordcount del adoquery.

Estamos hablando de distintos tipos de aplicaciones, a lo que puedo ver en tu ejemplo tu trabajas con aplicaciones de consola, yo no, yo trabajo con aplicaciones vcl. Asumí por la pregunta de dany2014 en la que hace referencia a un dbgrid y un dbedit que el trataba de generar una aplicación vcl, con componentes visuales de la paleta de herramientas de delphi que seleccionas y pegas en un formulario con propiedades por default que el programador no necesita configurar, solo el acceso a la base de datos en el componente adoconnection, la conexion en el adoquery y la sentencia de SQL ya sea en diseño o por código para acceder a los registros de la tabla alumnos que menciona, de tal forma que una vez abierto el adoquery, solo llamar a la propiedad recordcount de ese componente para obtener el numero de registros y visualizarlo en algún lugar.

No se nada de aplicaciones de consola, solo desarrollo aplicaciones vcl con bases de datos en el esquema cliente/servidor.

Una disculpa, entendí mal, retiro todo lo dicho.

Neftali [Germán.Estévez] 11-12-2014 11:19:28

Buenas. Intentaré aportar mi granito de arena al tema.

Cita:

Empezado por dany2014 (Mensaje 486304)
...lo que deseo es poder contar la cantidad de registros del dbgrid asociado a esa tabla

Antes de nada decir que para mi esto "no tiene sentido" estrictamente, si entendemos lo que es un DBGrid.
Para mi un DBGrid no es más que una ventana para ver determinados registros de una tabla. El grid en si, NO TIENE REGISTROS. Simplemente nos está mostrando unos cuantos. Cuando nos movemos arriba y abajo lo único que hacemos es mover la ventana para ver unos cuantos de los anteriores o unos cuantos de los que hay más abajo.

OTRO EJEMPLO:
Mirar un Grid es como mirar con una LUPA una hoja y preguntar ¿Cuantas lineas tiene la LUPA? Las líneas NO ESTÁN EN LA LUPA, siguen estando en la hoja. Si mueve la LUPA arriba y abajo veo líneas diferentes y si cambio de LUPA veo más o menos líneas, pero LA LUPA EN SI NO TIENE LINEAS, sólo las visualiza.


Dicho esto y espero que se haya entendido...

Cita:

Empezado por edgargh (Mensaje 486316)
si lo que necesitas es obtener el numero de registros de tu dbgrid, lo mas comun es hacerlo directamente a traves del dataset asociado (query o table).

Yo diría que es la única forma de hacerlo (no la más común). No tenemos un Grid.Count. Hablando siempre de DBGrid genérico. Tal vez haya casos particulares en los que exista algo así, pero eso no es común, ni recomendable creo.


Cita:

Empezado por edgargh (Mensaje 486370)
¿El funcionamiento de la propiedad recordcount de un TDataset en delphi depende del manejador de base de datos que se utilize?, no lo sabia, yo trabajo con sql server y funciona, ignoraba que con otros no. ¿Con que manejador de base de datos no funciona la propiedad recordcount de un Tdataset?

También de los componentes de conexión.
Por ejemplo habéis hablado de ADO. Estos componentes (realmente potentes) pueden trabajar en 2 modos. Utilizando "cursores cliente" y "cursores Servidor". Revisad las propiedades CursorLocation de TADOConnection, por ejemplo. No se pueden usar estas propiedades con todos los gestores, sino que dependen también del sistema al que nos estemos conectando. Por ejemplo, con SQL Server, se puede trabajar en ambos modos. Con bases de datos Access, sólo en "modo Cliente".

Cita:

Empezado por edgargh (Mensaje 486375)
Por ejemplo si trabajas con Tdatasets de ADO o DBExpress, que segun yo son los mas comunes y en los cuales puedes hacer la conexion con una infinidad de manejadores de bases de datos (incluyendo interbase), no tendrias el problema que mencionas

He de corregirte aquí. Tal y como he dicho antes, por ejemplo en ADO+SQL Server puedes trabajar en "modo cursor Server-side" y en ese caso las propiedades como Recordcount siempre devuelven -1. Es una forma de decirte que "no se están cargando todos los registros en memoria". Es estos casos tal y como se ha comentado, la fiorma es utilizar un SELECT...COUNT.

Cita:

Empezado por ElDioni (Mensaje 486407)
...me sale el número total de registros que hay en la consulta realizada.
como no he trabajado con otras bases de datos para mi esto también es lo normal.

Utilizando SGBD (frente a las Bases de Datos de escritorio) el comportamiento "normal" creo que sería el otro. No es aceptable que un SGBD devuelva todos los registros o los cargue todos en una tabla al hacer un SELECT.

Cita:

Empezado por edgargh (Mensaje 486412)
Te consta lo que dices?, lo haz hecho con un adoquery por ejemplo?, no te ha funcionado el recordcount?

Como he dicho, dependiendo de cómo esté configurado y contra qué BD/SGBD devolverá -1 o el número correcto de registros.

Cita:

Empezado por Casimiro Notevi (Mensaje 486419)
Desconozco cómo trabajan los componentes ADO que estás usando.
E insisto en que un query de consulta a una tabla no devuelve el número de registros que cumplen la condición, salvo que vayas al último.

En el caso de ADO, puede ser que ambos tengáis razón. Como he dicho permite comportamientos diferentes.

Un saludo.

orodriguezca 11-12-2014 14:25:59

Cita:

Empezado por edgargh (Mensaje 486461)
ok, gracias por el ejemplo, ya me queda claro de donde vienen las discrepancias entre los 2 en eso del recordcount del adoquery.

Estamos hablando de distintos tipos de aplicaciones, a lo que puedo ver en tu ejemplo tu trabajas con aplicaciones de consola, yo no,...


edgargh, No trabajo con aplicaciones de consola, lo mio también es form/vcl Cliente-Servidor, esto solo fue una forma cómoda de colocar en un solo sitio los elementos en cuestión para el ejemplo. Pero estoy de acuerdo contigo, el comportamiento por defecto de un TADOQuery (cursores del lado del cliente) devuelve el valor esperado en la propiedad RecordCount.


Neftali, excelente resumen, Gracias.

dany2014 11-12-2014 23:04:55

HOla gente, muchas gracias por los datos aporatdos, me sirvio bastante y de hecho con recorcount, salio lo que deseaba, hice el recordcount, y lo almacene en tbedit, lo necesitaba por que la tabla de alumnos aprobados de un curso, y lo almacene la cant en otra tabla,..... una ultima consulta, si alguien tiene algun procedure para verificar que el dni que ingreso en un tbdedit sea del tipo correcto, osea '40.369741' sea correcto y cualquier otro que tenga un caracter que no sea numnerico se incorrecto x ej: 'PO1234RE' 'el num ingresado no es un dni'.... muchas gracias... este mundo delphi es bastante amplio me queda mucho por descrubir...

Casimiro Notevi 11-12-2014 23:55:09

Preguntas distintas en hilos distintos.
También puedes buscar por los foros, que es un tema que se ha tratado infinidad de veces.
Como siempre aconsejamos a los nuevos, no olvides leer nuestra guía de estilo, gracias por tu colaboración :)


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

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