Knud Schröder: (MySQL) Bekomme die Reihen nicht wie gewünscht gezählt

Hallo,

In einer Tabelle buchen eine ganze Reihe von Mitarbeitern Tag für Tag,
Monat für Monat.Das heisst, es gibt in einem gewissen Zeitraum viele Mitarbeiter, die viele Buchungen getätigt haben.
Jetzt interessiert mich, wieviele Mitarbeiter denn nun im Endeffekt schon buchen, unabhängig wieviele.

Mit
select personalnummer,count(*) from buchungen group by personalnummer;
werden mir die Anzahl der Buchungen je Personalnummer gezeigt.
Mit
select count(*) from buchungen;
Alle Buchhungen überhaupt.

Ich hab aber leider keine Ahnung, wie ich personalnummern denn schließlich gebucht haben. Aber vielleicht jemand von Euch?

Gruß,

Knud

  1. Hi Knud

    In einer Tabelle buchen eine ganze Reihe von Mitarbeitern Tag für Tag,
    Monat für Monat.Das heisst, es gibt in einem gewissen Zeitraum viele Mitarbeiter, die viele Buchungen getätigt haben.
    Jetzt interessiert mich, wieviele Mitarbeiter denn nun im Endeffekt schon buchen, unabhängig wieviele.

    Sehe ich das richtig, du willst die Anzahl der Mitarbeiter welche
    in einem bestimmten Zeitraum gebucht haben?

    select count(mitarbeiter.mitarbeiter)
     from mitarbeiter
     inner join buchungen
        on (mitarbeiter.mitarbeiter = buchungen.mitarbeiter)
     where buchungen.datum between datum1 and datum2

    Ich gehe jetzt einfach mal davon aus, du hast auch eine
    eigene Tabelle für die Mitarbeiter, dann zählst du
    alle Mitarbeiter, welche mindestens ein Eintragung
    in der Buchungstabelle im betreffenden Zeitraum haben.

    Gruss Daniela

    1. Hi

      select count(mitarbeiter.mitarbeiter)
      from mitarbeiter
      inner join buchungen
          on (mitarbeiter.mitarbeiter = buchungen.mitarbeiter)
      where buchungen.datum between datum1 and datum2

      Leider zählt er trotzalledem dann _alle_ Buchungen in diesem Zeitraum.

      Geht nicht vielleicht so ne Art count(count(*))?

      Gruß,

      Knud

      1. Hi

        Leider zählt er trotzalledem dann _alle_ Buchungen in diesem Zeitraum.

        Upsi, du hast völlig recht, das passiert mir dauernd *schäm*

        Geht nicht vielleicht so ne Art count(count(*))?

        Ich wüsste nicht wie, in normalem SQL würde ichs lösen mit

        select count(personen)
          from personen
          where exists (select *
                          from buchungen
                          where datum between datum1 and datum2)

        Dass ist aber ein SubSelect welcher MySQL leider nicht beherrscht.

        Im Moment fällt mir keinerlei Möglichkeit ein das ganze Problem
        ohne Subselect ohne n Script zu lösen. Spukt mir aber die
        ganze Zeit im Kopf rum das Problem.

        Gruss Daniela

        1. Hi Daniela,

          Im Moment fällt mir keinerlei Möglichkeit ein das ganze Problem
          ohne Subselect ohne n Script zu lösen.

          ist das nicht der klassische Anwendungsfall von temporären Tabellen
          in mySQL?

          Viele Grüße
                Michael

          1. Hi Michael

            ist das nicht der klassische Anwendungsfall von temporären Tabellen
            in mySQL?

            Ich hab mal Ludwigs Lösung mit dem distinct innerhalb des counts
            ausprobiert, sie scheint zu funktionieren, also nicht nötig.

            Viele setzen sich so für die Durchsetzung des HTML-Standards ein,
            einen Standard für SQL gibts schon viel länger, und die Umsetzung
            davon ist noch viel fürchterlicher mit proprietären Erweiterungen
            und einfachsten Sachen die nicht unterstützt werden. Im Moment
            kann MySQL zb ja noch nicht einmal SQL-92 :(. Der Distinct
            innerhalb von count sieht mir auch nicht wirklich sauber ein.

            Ich wäre für ein Banner, fully SQL-92/SQL-99... compliant...

            Gruss Daniela

            P.S. hab ich schonmal erwähnt das mir MySQL gehörig auf den
            Keks geht, vorallem im Vergleich zu DB/2?

            1. Hi Daniela,

              Ich wäre für ein Banner, fully SQL-92/SQL-99... compliant...

              das Problem dabei ist, daß ein solches Banner ja niemanden interessiert
              außer der Handvoll Implementierer hinter den Kulissen.

              P.S. hab ich schonmal erwähnt das mir MySQL gehörig auf den
              Keks geht, vorallem im Vergleich zu DB/2?

              Was die Implementierung einer _richtigen_ Datenbank angeht, so habe ich
              davor einen Heidenrespekt. Die Komplexität beispielsweise eines Webservers
              ist im Vergleich dazu m. E. völlig harmlos - der muß es ja 'nur' richtig
              machen.
              Insofern finde ich, daß sich mySQL schon recht tapfer schlägt.
              Ich erwarte gar nicht, daß es mit DB2 oder Oracle konkurrieren kann.

              Viele Grüße
                    Michael

  2. Hi,

    select personalnummer,count(*) from buchungen group by personalnummer;

    Da ich grad keine DB zur hand habe um es auszuprobiern rat ich mal ins blaue:

    select DISTINCT personalnummer from buchungen;
    sollte jede personalnummer nur einmal ausgeben.

    select DISTINCT count(personalnummer) from buchungen;
    Sollte die summer von den personalnummern ausgeben, wobei jeder personalnummer nur einmal gezählt wird.

    wie gesagt UNTESTED, ich weiß nicht wie DISTINCT auf das count() reagiert, bzw ob es wie erwartet reagiert.

    lg
    Ludwig

    1. Hi,

      select DISTINCT count(personalnummer) from buchungen;
      Sollte die summer von den personalnummern ausgeben, wobei jeder personalnummer nur einmal gezählt wird.

      hmm, leider nicht und aus dem Ergebnis werd ich nicht so schlau.
      Es wird was gezählt, es deutlich weniger angezeigt als ohne Distinct, aber was ... keine Ahnung.

      tests are going on...

      Knud

      1. das ist die anzahl der User, die gebucht haben mindestens einmal gebucht haben.

        Hi,

        select DISTINCT count(personalnummer) from buchungen;
        Sollte die summer von den personalnummern ausgeben, wobei jeder personalnummer nur einmal gezählt wird.

        hmm, leider nicht und aus dem Ergebnis werd ich nicht so schlau.
        Es wird was gezählt, es deutlich weniger angezeigt als ohne Distinct, aber was ... keine Ahnung.

        tests are going on...

        Knud

        1. das ist die anzahl der User, die gebucht haben mindestens einmal gebucht haben.

          kann eigentlich nicht sein.

          mit
          select personalnummer, count(*) from buchungen where ndatum like '2002-01%' group by personalnummer;
          werden mir doch auch alle personalnummern gezeigt, die mindestens ein mal gebucht haben (sonst wären sie auch nicht in der Tabelle *g*).

          Mit dem DISTINCT sinds deutlich weniger und ich kann halt nicht erkennen warum gerade die angezeigt werden.

          Gruß,

          Knud

          1. ja aber mit distinct verhindert man, das User doppelt angezeigt werden, und so wie ich es aus deiner frage erlesen habe, wolltest du alle user haben die gebucht haben und eine Mehrfachausgabe soll verhindert werden und das geht mit distinct.

            das ist die anzahl der User, die gebucht haben mindestens einmal gebucht haben.

            kann eigentlich nicht sein.

            mit
            select personalnummer, count(*) from buchungen where ndatum like '2002-01%' group by personalnummer;
            werden mir doch auch alle personalnummern gezeigt, die mindestens ein mal gebucht haben (sonst wären sie auch nicht in der Tabelle *g*).

            Mit dem DISTINCT sinds deutlich weniger und ich kann halt nicht erkennen warum gerade die angezeigt werden.

            Gruß,

            Knud

            1. ja aber mit distinct verhindert man, das User doppelt angezeigt werden, und so wie ich es aus deiner frage erlesen habe, wolltest du alle user haben die gebucht haben und eine Mehrfachausgabe soll verhindert werden und das geht mit distinct.

              und genau das macht doch auch schon das count mit dem group by, oder etwa doch nicht?

              mit fragendem Blick,

              Knud

              1. Hallo Curt

                und genau das macht doch auch schon das count mit dem group by, oder etwa doch nicht?

                nein

                deine Abfrage:
                select personalnummer, count(*) from buchungen where ndatum like '2002-01%' group by personalnummer;

                gibt an, welche Personalnummer wieviele Buchungen vorgenommen hat. Du möchstest aber wissen, wieviele Personalnummern Buchungen vorgenommen haben. Dazu genügt es

                select , count(distinct personalnummer) from buchungen where ndatum like '2002-01%';

                anzugeben.

                Noch ein Tipp: Verwende statt like lieber DATE_FORMAT. Das macht dich unabhängig von gespeicherten Datumsformaten. In deinem Beispiel könnte das z.B. so aussehen

                select , count(distinct personalnummer) from buchungen where FATE_FORMAT(ndatum,'%c.%y)='1.02';

                %c steht für Monatszahlen ohne führende Null und %y für zweistellige Jahreszahlen.

                Trennzeichen (hier der Punkt) ist beliebig. Mehr dazu http://mysql.com/documentation/mysql/bychapter/manual_Reference.html#Date_and_time_functions

                Viele Grüße

                Antje

                1. Hi Antje,

                  Noch ein Tipp: Verwende statt like lieber DATE_FORMAT.

                  mein Stil wäre auch das nicht.
                  Ich will doch nicht in einer WHERE-Klausel, die vielleicht ein paar
                  Millionen mal ausgewertet wird, eine Konvertierungsfunktion aufrufen.

                  Womöglich schalte ich auf diese Weise sogar einen ansonsten möglichen
                  Indexzugriff implizit aus! Dann kann mich der Spaß einen Faktor an 1000
                  und mehr an Performance kosten.

                  Ich würde dazu tendieren, das Datum als UNIX time stamp (32 bit unsigned
                  integer) zu speichern, in meinem 3GL-Anwendungsprogramm die Konvertierung
                  zwischen welchem externen Datumsformat auch immer und diesem time stamp
                  durchführen und dann einfach einen Zahlenvergleich machen.
                  Falls ich ein festes Tagesraster benötige, dann kann ich ja die Zeitpunkte
                  jeweils auf 00:00:00 Uhr fixieren.

                  Das macht dich unabhängig von gespeicherten Datumsformaten.

                  Yep, aber meine Methode auch.

                  Datumsformate sind Visualisierungen, die will ich aus der Datenbank
                  komplett heraus halten.

                  Viele Grüße
                        Michael

      2. Hi,

        select DISTINCT count(personalnummer) from buchungen;
        Sollte die summer von den personalnummern ausgeben, wobei jeder personalnummer nur einmal gezählt wird.

        hmm, leider nicht und aus dem Ergebnis werd ich nicht so schlau.
        Es wird was gezählt, es deutlich weniger angezeigt als ohne Distinct, aber was ... keine Ahnung.

        was willst du jetzt als ergebniss ? Die anzahl ( = 1 zahl) der personen die etwas gebucht haben, bzw welche in der tabelle stehen ?

        zu meinen obigen sql statement man könnte auch mal:

        select count(distinct personalnummer) from buchungen; versuchen...

        Distinct bewirkt das ein wert nur einmal verwendet wird. count zählt dann diese werte zusammen, das ergebniss sollte die menge der personen sein die mindestens eine buchung gemacht haben.

        lg
        Ludwig

    2. Hi Ludwig

      wie gesagt UNTESTED, ich weiß nicht wie DISTINCT auf das count() reagiert, bzw ob es wie erwartet reagiert.

      Gemäss MySQL Manual: http://www.mysql.com/doc/D/I/DISTINCT_optimisation.html
      wird daraus ein Group By auf allen Spalten, also in dem Fall auf count()
      weil es die einzige Spalte im Ergebnis ist. Es dürfte also keinerlei
      Einfluss ausser dem Ausbremsen der Query (falls MySQL nicht automatisch
      wegoptimiert) haben.

      Gruss Daniela