Mailinglisten-Archive |
Frank Oellien schrieb am Samstag, den 9. Oktober 1999: > I habe folgendes Problem. Ich habe eine Tabelle, die folgendermassen > aufgebaut ist: > > NSCNr | CellID | Konz. > 123 | 1 | 2 > 123 | 2 | 2 > 123 | 3 | 2 > 123 | 1 | 2.5 > 123 | 2 | 2.5 > 124 | 1 | 2 > 124 | 3 | 3 > 125 | 1 | 1.6 > 125 | 2 | 1.5 > 126 | 2 | 1.5 > 126 | 4 | 1.5 > > Als Ergebnis moechte ich gerne die Anzahl aller verschiedenen (!) > NSCNr fuer eine CellID haben: > > CellID | count(NSCNr) > 1 | 3 > 2 | 3 > 3 | 2 > 4 | 1 > > Der Befehl: > select CellID, count(NSCNr) from tgi group by CellID; > fuehrt allerdings nur zum Zaehlen aller NSCNr (was ja auch korrekt > ist aber nicht meinem Wunsch entspricht): > > CellID | count(NSCNr) > 1 | 4 > 2 | 4 > 3 | 2 > 4 | 1 > > Wie muss die Anfrage richtig lauten? Dafür gäbe es in SQL die COUNT-Variante 'COUNT(DISTINCT ...)', mit der Deine Abfrage so aussehen würde: SELECT CellID, COUNT(DISTINCT NSCNr) FROM tgi GROUP BY CellID; Leider unterstützt MySQL dieses COUNT(DISTINCT ...) aber erst ab Version 3.23.x! Falls Du eine ältere MySQL-Version benutzt, kommt man nur auf Umwegen an das gewünschte Ergebnis: - Selber auf der Anwendungsseite zählen: SELECT DISTINCT NSCNr, CellID FROM tgi ORDER by CellID; Und dann für jede CellID die Anzahl der ausgegebenen Zeilen mitzählen. - Mit Hilfe einer temporären Hilfstabelle: CREATE TABLE tmp ( NSCNr INT, CellID INT ); INSERT INTO tmp SELECT DISTINCT NSCNr, CellID FROM tgi; SELECT CellID, COUNT(NSCNr) FROM tmp GROUP BY CellID; DROP TABLE tmp; Der entscheidende Punkt ist wieder das SELECT DISTINCT, welches sicherstellt, daß keine Duplikate in der temporären Tabelle landen. Nachteil ist hier vorallem der zusätzliche Platzbedarf für die temporäre Tabelle. Falls diese Abfrage mehrfach gleichzeitig laufen kann, muß man zudem darauf achten, daß es keine konkurrierenden Zugriffen auf die temporäre Tabelle geben kann - entweder durch Locking oder indem die temporäre Tabelle jedesmal einen anderen, eindeutigen Namen bekommt. Letzteres geschieht ab MySQL V3.23.x automatisch, wenn man CREATE TEMPORARY TABLE nutzt. - Mit Hilfe eines Self-Joins: SELECT t1.CellID , COUNT(t1.NSCNr)-COUNT(t2.NSCNr) AS cd FROM tgi AS t1 LEFT JOIN tgi AS t2 ON t1.NSCNr=t2.NSCNr AND t1.CellID=t2.CellID AND t1.Konz<t2.Konz GROUP BY CellID; Die Ausgangsidee dabei ist, daß man zuviel gezählte Zeilen wieder abziehen will. Welche sind das aber? Das sind alle die Zeilen, wo es noch anderen Datensätze mit der gleichen (CellID, NSCNr)- Kombination gibt! Das könnte man mit einem LEFT JOIN so testen: FROM tgi AS t1 LEFT JOIN tgi AS t2 ON t1.NSCNr=t2.NSCNr /* gleiche NSCNr */ AND t1.CellID=t2.CellID /* gleiche CellID */ AND t1.Konz!=t2.Konz /* aber verschiedene Zeilen */ Wenn die Tabelle einen Primärschlüssel besitzt, dann sollte man statt des Konz-Vergleichs die Primärschlüssel auf Verschiedenheit testen - Ziel ist halt sicherzustellen, daß zwei verschiedene Zeilen verbunden werden! Statt mit '!=' zu vergleiche, ist es aber geschickter, '<' zu verwenden. Denn so gibt es pro (CellID, NSCNr)-Gruppe genau eine Ergebniszeile mit NULL-Werten auf der t2-Seite: nämlich für den t1-Datensatz mit der größten ID (hier: größtes Konz). Jetzt braucht man also nur noch die NULL-Werte in einer Spalte der t2-Seite zu zählen und hat die gewünschte Anzahl verschiedener Werte. Diese Zählen der Nullwerte ginge z.B. mit SUM( IF( ISNULL(t2.NSCNr), 1, 0 ) Hübscher (und vermutlich schneller) ist aber, die Anzahl der NULL-Werte als Differenz der Gesamtanzahl=COUNT(t1.NSCNr) mit der Zahl der Nicht-NULL-Werte=COUNT(t2.NSCNr) zu berechnen. Hmm, eben - kurz vorm abschicken der Mail - fiel mir noch eine Verbesserung ein: Statt die NULL-Werte irgendwie kompliziert zu zählen, kann man per WHERE-Klausel die Ergebniszeilen mit rechtem NULL-Teil herausfiltern und braucht dann nur noch ein einfaches COUNT im linken t1-Teil. Das hier ist also meine LEFT JOIN-Lösung: SELECT t1.CellID, count(t1.NSCNr) AS NSCNr FROM tgi AS t1 LEFT JOIN tgi AS t2 ON t1.NSCNr=t2.NSCNr AND t1.CellID=t2.CellID AND t1.id<t2.id WHERE t2.NSCNr IS NULL GROUP BY CellID; Dabei muß id eine Spalte mit Unique-Index sein oder gleich der Primärschlüssel. (Sonst könnte es beim '<'-Vergleich mehrere größte Elemente geben und es würde zu viel gezählt.) Ciao, Martin -- Martin Ramsch <m.ramsch_(at)_computer.org> <URL: http://home.pages.de/~ramsch/ > PGP KeyID=0xE8EF4F75 FiPr=5244 5EF3 B0B1 3826 E4EC 8058 7B31 3AD7 --- *** Abmelden von dieser Mailingliste funktioniert per E-Mail *** an mysql-de-request_(at)_lists.4t2.com mit Betreff/Subject: unsubscribe
php::bar PHP Wiki - Listenarchive