Anzahl Datensätze



  • Hi zusammen
    ich will bevor ich meine SQL-Query sende wissen wieviele Datensätze ich für bestimmte Anfrage bekomme. wenn ich ODBCFieldCount nehme, gebt er mir immer 1 aus. Ein Blick in die MSDN verrät dann, dass ODBCFieldcount nur zu gebrauchen ist wenn man einen neuen Datensatz eingefügt hat und dann wissen will wieviele Records. Gibt es da irgend ne schöne MFC Methode die mir die Anzahl an Datensätzen zurück gibt? Oder muss ich da ein direkten SQL-Befehl ausführen und die Funktionen der DB nutzen? (in meinem Fall MS-SQL)

    Danke für jeden Tip



  • Also, die SQL-Funktion wäre:

    select count(*) from [Tabelle]
    

    🙂



  • Für ODBC gibt es leider nichts schnelles. IMHO muss man alle Datensäze selbst zählen.

    Eben ein SELECT count(*);



  • Die CRecordset-Klasse hat auch noch irreführenderweise ein GetRecordCount - das funktioniert aber erst, wenn man einmal über alle Datensätze gelaufen ist. 🙄



  • Hm OK.
    Ist ein Select count * langsamer wie wenn ich select [1] Spalte from... weil ich muss möglichst schnell sein, da im laufe der Zeit doch einiges zusammen kommt. (ca 2000 Datensätze Pro Tag über ca 8 Jahre)



  • Also, wenn das soooooo viel ist, würde ich schlimmstenfalls einen Trick machen:
    Du machst einen On-Insert-Trigger auf die Tabelle (delete natürlich auch) und zählst da hoch bzw. runter und speicherst das in einer Hilfstabelle, wo nur das drin steht. 😃

    Das wär jedenfalls ne Lösung, falls select count wirklich zu langsam ist. 🙂



  • wofür muss du die datensätze zählen?



  • Ich muss die Datensätze zählen um den Benutzer dann zu fragen "Sind sie sicher dass sie 1.937.365 Datensätze abfragen wollen?" 😃
    Der user soll dann selbst entscheiden und evtl. die suche noch etwas einschränken können. Des weiteren soll mir das auch sagen wieviele Teile z.B. in der Frühschicht produziert worden sind. Wieviele IO wieviele NIO ... der BR wird sich freuen! 😃

    @Estartu: Hä? Hab ich glaub nicht ganz verstanden wieso soll ich das in ner Hilfstabelle speichern? Ich will ja auf jede Anfrage getrennt reagieren. Außerdem sollte eine weitere Tabelle vermieden werden, da die Tabellen Übersicht für diesen Tester schon stoltze 21 Seiten umfasst. 😮



  • Tja, wenn das mit Where ist, dann geht nur select count. Ich hatte deinen ersten Post irgendwie nicht richtig gelesen. 🙄

    Aber, ich glaube, sooo langsam ist das gar nicht. 🙂



  • Frage, wo steht dann meine Anzahl drin? Ich hab das jetzt mal so angefangen.

    CDatabase m_db;
    	m_db.Open( _T( "ACR" ), FALSE,true, _T( "ODBC;UID=anyusr;PWD=anyusr" ),false);
    	m_db.ExecuteSQL("Select count(*) from [dbo].[TRWErgebnisse]");
    

    Wo steht jetzt mein Ergebnis von count?

    (zur Zeit: ich sollte für count halt unter ca 2Sekunden bleiben)



  • Gib der Spalte doch ne richtige Bezeichnung:

    select count(*) as anzahl from [tabelle]
    

    dann hast du im ersten Record des Recordset die Anzahl..

    open
    

    nicht

    ExecuteSQL
    


  • geht sowas denn nicht ohne zusätzliche Spalte? Ich hab in der Tabell mittlerweile ca 160 Spalten und 5 virtuelle Spalten, also kalkulierte Felder. Ich will irgendwie drum rum kommen nochmal ne Spalte zu verwenden. Und wieso gleich beim open das SQL-State mitgeben? Warum nicht mit execute SQL?



  • Du sollst nicht eine neue Spalte oder gar Tabelle anlegen. 🙄

    So, wie das beschrieben wurde, wird eine Art "temporäre Tabelle" gemacht, wo genau eine Spalte drin ist (anzahl) und die nur eine Zeile hat.
    Diese "Tabelle" landet mit dem Open Befehl in dem Recordset und du hast die Anzahl. 🙂



  • Okay, das mit dem Open hab ich blöd geschrieben und das mit der Bezeichnung hast du nicht richtig verstanden 🙂

    CDatabase db;
            db.Open( _T( "ACR" ),FALSE,true,_T("ODBC;UID=anyusr;PWD=anyusr"),false);
    	CRecordset Set(&db);
    
    	CString strAnzahl;
    	CString strSQL = "Select count(*) as anzahl from [dbo].[TRWErgebnisse]";
    
    	Set.Open(CRecordset::dynaset | CRecordset::forwardOnly, strSQL);
            Set.MoveFirst()
    	if(!Set.IsEOF())
    	{
    	        Set.GetFieldValue("ANZAHL", strAnzahl);
    	}
    
    	Set.Close();
    
            // ungetestet getippt, könnten Fehler drin sein
    


  • aaahhhh OK.
    Jetzt hab ich das verstanden. Nur wenn ich den Source so probiere bekomme ich einen Fehler mit dem ich nichts anfangen kann

    ---------------------------
    ACRSQL
    ---------------------------
    Datensatzgruppe unterstützt nur Vorwärtsbewegung.
    ---------------------------
    OK
    ---------------------------

    Ob Debug oder Release ist egal! Was ist falsch? ~(Ansonsten TipTop, ohne Probieren! Nur ein Semikolon hat gefehlt nach move first.)~

    .



  • Las mal das MoveFirst weg, damit springt man zum ersten record, allerdings wird das RecordSet mit ForwardOnly geöffnet, da kann er natürlich nicht zurück springen 🙂 Emdweder das ForwardOnly wegnehmen, oder das MoveFirst(), dann sollte es klappen..



  • WOW! Jetzt geht es! Hab jetzt noch kleine Anpassungen gemacht, und es geht genau so wie ich es wollte.
    Jetzt hab ich es so:

    CDatabase db; 
        db.Open( _T( "ACR" ),FALSE,true,_T("ODBC;UID=anyusr;PWD=anyusr"),false); 
    
    	CRecordset Set(&db); 
    
        CString strAnzahl; 
        CString strSQL = "Select count(*) as ANZAHL from [dbo].[TRWErgebnisse] where " + m_sResult; 
    
        Set.Open(CRecordset::dynaset | CRecordset::forwardOnly, strSQL); 
        if(!Set.IsEOF()) 
        { 
    		Set.GetFieldValue("ANZAHL", strAnzahl);
    		m_sSuchen = strAnzahl;
        } 
    
        Set.Close(); 
    	UpdateData(false);
    

    Ich würde jetzt noch gerne die Zeit ermitteln, die benötigt würde, um diese Anzahl an datensätzen rein zu holen.
    Mach ich mir da selber nen Timer und les solange Daten ein, wie der Zähler läuft, und Teil dann mein Ergebnis durch die Anzahl Datensätze des Timers und multiplizier es dann mit dem Timer oder geht das einfacher?
    Hab da was von QueryPerformanceCounter gelesen.
    Geht das mit der Methode?
    Vielen Dank auf jeden Fall schonmal für das bisher, echt hammers cool. 👍 😃



  • Ich hab das in meine Recordset-Basisklasse gebastelt:

    bool CBasisSet::Query()
    {
    	BOOL fResult = FALSE;
    	DWORD dwAnfang = GetTickCount();
    
    	try
    	{
    		if(!IsOpen())
    		{
    			fResult = Open();
    		}
    		else
    		{
    			fResult = Requery();
    		}
    	}
    	catch (CDBException* e)
    	{
    		CLog::Log(LOG_NR_DB_FEHLER, e->m_strError);
    		throw(e); // Weiterwerfen
    	}
    
    	DWORD dwEnde = GetTickCount();
    	CLog::Log(LOG_NR_DB_QUERY, _T("Tabelle: %s"), GetDefaultSQL());
    	CLog::Log(LOG_NR_DB_QUERY, _T("Where: %s"), m_strFilter);
    	CLog::Log(LOG_NR_DB_QUERY, _T("Order by: %s"), m_strSort);
    	CLog::Log(LOG_NR_DB_QUERY, _T("Dauer: %d ms"), dwEnde-dwAnfang);
    	CLog::Log(LOG_NR_DB_QUERY, _T("Erfolg? %b"), fResult);
    
    	return (fResult == TRUE);
    }
    

    CLog::Log ist eine Art TRACE und CString::Format in eins. 🙂
    Irgendwer meinte aber mal, GetTickCount wäre zu ungenau. 🙄



  • Das würde mich auch interessieren 🙂

    Aber über ODBC kenne ich keine Möglichkeit dazu, auch deine Methode funktioniert nur ungenau. Je nachdem wie stark der DB-Server belastet ist benötigt er mehr oder weniger Zeit.. Ne abschätzung ist da ziemlich schwierig.
    Wenn die Rückgabe der Datenbank nicht sortiert sein soll, könnteste immer nur einen Teil der Daten holen und dabei nen Progressbar oder sowas aktualieren.
    Sobald du aber sortierst ("order by xxx") muss die Datenbank eh alles aufbereiten und du hast keinen Vorteil, im Gegenteil - es müsste bei jeder Anfrage wieder sortiert werden...



  • WOW cool!
    Nur ein wenig Erklärung brauch ich noch.
    Du startest einfach nen TickCount machst dann die Query und dann wieder den End-Tickcount und ziehst die dann von einander ab. richtig?
    Sprich wenn ich eine Query mach die 100 Datensätze liefert, dann nimm ich dwEnde-dwAnfang/100 und weiß wie lange er für einen Datesatz braucht und dann kann ich: Anzahl Ergebnisse * (dwEnde-dwAnfang/100) und es sollte in etwa die Zeit sein, die er benötigt um die Datensätze zu holen.
    😃 Wie cool! 😃


Anmelden zum Antworten