Reinhard: Abfrageproblem bei einer nicht sauber normalisierten Tabelle

Hallo Forum,

ich hoffe, Ihr könnt mir helfen.

Ich habe eine Tabelle, die nicht sauber normalisiert ist. Im Großen und Ganzen istr das für die Programmbenutzung kein Problem.

Lediglich bei einer internen Statistik, die ich anfertige, bereitet es mir gerade Kopfzebrechen.

Hier die Strucktur:

ID|User|Punkte

Unter User können (das ist das Problem) mehrer User, durch Kommata getrennt enthalten sein. Die bekommen dann auch alle die in dieser Zeile vergebenen Punkte gutgeschrieben.

Nun möchte ich die gesamten in dieser Tabelle vergebenen Punkte errechnen.

Beispiel:

1|Hinz,Kunz|10
2|Fritz|20
3|Pit,Mike,Lutz|15

Die Query soll als Ergebniss 85 ergeben.

Wie werde ich dieser unnormalisierter Spalte in der benötigten Query Herr.

Ich habe schon mächtigst gesucht, bin bereits auf CASE und auf REGEXP '[[:<:]]...[[:>:]]' gestoßen, aber bekomme die Query auch nach Stunden suchen und versuchen nicht hin.

Bitte also daher hier um Hilfe,

Danke, Reinhard

  1. Ein Hauch einer Möglichkeit hättest du nur wenn du eine weitere Tabelle hast mit allen Usernamen (*nicht* Kommagetrennt) und wenn dein verwendetes DBMS MySQL lautet.

    1. Ein Hauch einer Möglichkeit hättest du nur wenn du eine weitere Tabelle hast mit allen Usernamen (*nicht* Kommagetrennt) und wenn dein verwendetes DBMS MySQL lautet.

      Hi,

      das ist zwar so, aber ich bezweifel, dass Du mit Deiner Behauptung Recht hast.
      Warten wir mal ab, was die Profis zu dem Thema sagen.

      Dennoch danke für die erste Antwort

      Reinhard

      1. tab1 ist deine o.g. Punktetabelle, tab2 die Tabelle der user

          
        SELECT GROUP_CONCAT(user), punkte  
        FROM (  
        	SELECT tab2.user, SUM(tab1.punkte) punkte  
        	FROM  tab1  
        	JOIN  tab2  
        		ON FIND_IN_SET(tab2.user, tab1.user) > 0  
        	GROUP BY tab2.user  
        ) tab  
        GROUP BY punkte  
        
        
        1. moin,

          die beiden gruppierungen kannst du dir sparen, laut seiner ergebnisliste will er eh alle punkte zusammen addiert haben und nicht aufgeteilt in den jeweiligen gruppen.

          des weiteren läufst du damit gefahr, dass du falsche ergebnisse bekommst, weil namen als teilmenge in anderen namen enhalten sein können.

          Ilja

          1. die beiden gruppierungen kannst du dir sparen, laut seiner ergebnisliste will er eh alle punkte zusammen addiert haben und nicht aufgeteilt in den jeweiligen gruppen.

            Ich sehe es anders, er will gruppiert nach Punkten, deiner M.n. müsste die Tabelle bspw. so aussehen
            'Kunz,Hinz', 3
            'Kunz,Hinz', 10
            'Kunz,Hinz', 2
            also die Gruppierungen in der Tabelle jedesmal exakt so wie im Ergebnis, das glaube ich aber eher weniger

            des weiteren läufst du damit gefahr, dass du falsche ergebnisse bekommst, weil namen als teilmenge in anderen namen enhalten sein können.

            Dafür ist FIND_IN_SET() zuständig

            1. Hi,

              Ich sehe es anders, er will gruppiert nach Punkten,

              Ich möchte nur die gesamten vergebenen Punkte ermitteln.

              Es geht also nur um 1 Zahl, die die Ergebnismenge liefern soll.

              Gruß, Reinhard

              1. Uups, das hatte ich ja komplett falsch verstanden, ich dachte dein Beispiel soll das Ergebnis darstellen.

                So gesehen ist die Lösung von @Ilja natürlich richtig.

                Sorry.

                1. Uups, das hatte ich ja komplett falsch verstanden, ich dachte dein Beispiel soll das Ergebnis darstellen.

                  So gesehen ist die Lösung von @Ilja natürlich richtig.

                  Sorry.

                  Das ist ganz und gar kein Problem.

                  Vielen Dank aber trotzdem für Deine Mithilfe.

                  Grüße, Reinhard

        2. tab1 ist deine o.g. Punktetabelle, tab2 die Tabelle der user

          SELECT GROUP_CONCAT(user), punkte
          FROM (
          SELECT tab2.user, SUM(tab1.punkte) punkte
          FROM  tab1
          JOIN  tab2
          ON FIND_IN_SET(tab2.user, tab1.user) > 0
          GROUP BY tab2.user
          ) tab
          GROUP BY punkte

          
          >   
            
          Danke für den Code, aber so ganz ohne Erklärung verstehe ich ihn nicht :-(  
            
          Gruß, Reinhard
          
          1. Danke für den Code, aber so ganz ohne Erklärung verstehe ich ihn nicht :-(

            Sorry, aber der Code ist eh für ein anderes Problem, ich hatte dein erstes Posting falsch interpretiert.

  2. moin,

    ich hoffe, Ihr könnt mir helfen.

    für ein frisches bier mache ich alles.....

    Ich habe schon mächtigst gesucht, bin bereits auf CASE und auf REGEXP '[[:<:]]...[[:>:]]' gestoßen, aber bekomme die Query auch nach Stunden suchen und versuchen nicht hin.

    das brauchst du alles nicht, es gibt dafür einen kleinen trick. ich kann dir die komplette abfrage liefern, aber ich verrate dir erst mal den trick und vielleicht kannst du ja den rest erstellen.

    Du brauchst zwei funktionen, die du geschickt einsetzen musst, nämlich REPLACE UND LENGTH. wie genau die funktionen heißen, hängt ein wenig von deinem DBMS ab. aber schau dir mal folgendes an....

    LENGTH(user) - LENGTH(REPLACE(user, ',', '')) + 1

    Ilja

    1. Hi Ilja,

      für ein frisches bier mache ich alles.....

      Liebend gerne...und ich trink auch selber eines mit *g*
      Leider (oder in vielen anderen Fällen 'zum Glück') geht noch nicht alles virtuell :-(

      Du brauchst zwei funktionen, die du geschickt einsetzen musst, nämlich REPLACE UND LENGTH. wie genau die funktionen heißen, hängt ein wenig von deinem DBMS ab. aber schau dir mal folgendes an....

      Ich benutze mysql, Version 5

      LENGTH(user) - LENGTH(REPLACE(user, ',', '')) + 1

      Aah, jetzt fällt der Groschen, aber ich hab zugegebenerweise schon etwas dafür gebraucht ;-)

      Du versuchst über die Differenz des Gesamttextes und des um die kommata verkürzten Gesamttextes an die Anzahl der Kommata zu kommen und hast folglich einen Namen mehr im Feld als Du kommatas hast, deshalb die Addition mit 1.

      Ok, den Trick habe ich verstanden, aber die Umsetzung in mywsql-Sprache fällt mir trotzdem noch etwas schwer. Vielleicht aber auch, weil ich inzwischen nach etlichen Stunden Code schreiben "gefühlt" nur noch Spagetti im Kopf habe ;-)

      Ich versuch mal:

      SELECT  
      SUM(  
      (LENGTH(User) - LENGTH(REPLACE(User, ',', '' ))+1)  
      *Punkte)  
      FROM Tabelle
      

      Ist das so richtig?

      Gruß, Reinhard

      1. Ich versuch mal:

        SELECT

        SUM(
        (LENGTH(User) - LENGTH(REPLACE(User, ',', '' ))+1)
        *Punkte)
        FROM Tabelle

        
        >   
        >   
        > Ist das so richtig?  
        >   
          
        Das konnte ich grade mal testen und es funktioniert tadellos.  
          
        Nun ist das Problem im Echtbetrieb doch noch etwas verzwickter.  
          
        Die Tabelle sieht nämlich so aus:  
          
        ID|tabellenverweis|spielID|status|punkte  
        1|A|1|neu|20  
        2|A|2|neu|30  
        3|B|2|neu|25  
        4|Z|22|alt|50  
          
        A bedeutet, dass ich die Spielerkombination in Tabelle spiel\_A finde, B bedeuted, dass ich sie in spiel:B finde.  
          
        spiel\_A:  
        spielID|spieler  
        1|Karl,Theo  
        2|Peter,Franz  
        3|Gerd,Tom  
          
        spiel\_B:  
        spielerID|spieler  
        1|Theo,Tom  
        2|Karl  
          
        Wie muß nun meine Abfrage lauten, damit ich als Ergebniss der neu verteilten Gesamtpunkte die Summe 125 erhalte?  
          
        125=2\*20+2\*30+1\*25  
          
        Gruß, Reinhard  
          
          
        
        
        1. moin,

          auch wenn du eventuell nichts dafür kannst und vor allem es nicht ändern kannst, dein datendesign ist "unvorteilhaft", um es mal milde auszudrücken. das riecht ein wenig nach steinzeit.

          Wie muß nun meine Abfrage lauten, damit ich als Ergebniss der neu verteilten Gesamtpunkte die Summe 125 erhalte?

          am besten benutzt du dafür den UNION ALL Mengenoperator, sprich du hast zwei abfragen, eine für Tabelle A und eine für Tabelle B, die du dann zusammen fügst und die Summe darüber bildest.

          SELECT SUM(z.Anzahl) Meine_Summe
          FROM (SELECT (LENGTH(a.spieler) - LENGTH(REPLACE(a.spieler, ',', '')) +1) * t.Punkte Anzahl
                FROM Tabelle t
                INNER JOIN spiel_A a ON a.spielID = t.spielID
                WHERE t.tabellenverweis = 'A'
                UNION ALL
                SELECT (LENGTH(b.spieler) - LENGTH(REPLACE(b.spieler, ',', '')) +1) * t.Punkte
                FROM Tabelle t
                INNER JOIN spiel_B b ON b.spielID = t.spielID
                WHERE t.tabellenverweis = 'B'
               ) z
          ;

          das würde ich jetzt als am übersichtlichsten ansehen. es gibt noch andere möglichkeiten mit einer unterabfrage oder aber joins. aber dann wird nicht ganz klar, was du damit machen willst.

          Ilja