RFZ: kompliziertes mysql select

Moin,
ich weiss garnicht ob dieses Select möglich ist, da ich von MySQL noch nicht so wahnsinnig viel Ahnung hab im Bezug auf abhängige Selects...

Ok, meine Tabelle "posts" siehst so aus:

id    tid   pid
---------------
1     1     0
2     1     1
3     1     1
4     1     3
5     5     0
6     5     5
7     5     6
8     8     0
9     1     2

Das stellt eine Forumstruktur dar:

Thread1:

  • Post 1
      - Post 2 (aw Post 1)
        - Post 9 (aw Post 2)
      - Post 3 (aw Post 1)
        - Post 4 (aw Post 3)

Thread5:

  • Post 5
      - Post 6 (aw Post 5)
        - Post 7 (aw Post 6)

Thread8:

  • Post 8

Diese Struktur darzustellen ist kein Problem, das Sortieren der Threads (Threads sind pid=0) nach der letzten Antwort macht mir aber Probleme.
Ich müsste dazu in einem Select alle Datensätze mit pid=0 auswählen, zusätzlich müsste ich aber die letzte ID des Postings wissen, dessen tid die id des Threads ist... Verständlich? ;)

Ich müsste soein Ergebnis bekommen:
id    tid    pid    lastawid
----------------------------
1     1      0      9
5     5      0      7
8     8      0      8/0  (egal, gibt ja keine Antwort)

Und das müsste ich dann nach lastawid sortieren können...

Ich hoffe jemand weiss wie ich sowas anstellen kann, Danke ;)

greetz RFZ

  1. Hello,

    id    tid   pid

    1     1     0
    2     1     1
    3     1     1
    4     1     3
    5     5     0
    6     5     5
    7     5     6
    8     8     0
    9     1     2

    id    tid   pid   lvl
     -----------------------
     1     1     0      1
     2     1     1      2
     3     1     1      2
     4     1     3      3
     5     5     0      1
     6     5     5      2
     7     5     6      3
     8     8     0      1
     9     1     2      3

    I.d.R. will man ja gar nicht den ganzen Baum auf einmal sehen, sondern immer nur eine Ebene zusätzlich einblenden oder wieder ausblenden. Dazu kann man sich einfach den Level mit abspeichern beim Anlegen des abhängigen Posts. Wenn man dann einen  Select über die Levels macht, hat man schon eine ganze Menge gewonnen. Ob meine Level-Spalte da nun stimmt, weiß ich nicht. Versuch mal, es zu überprüfen.

    Je weiter man in die Tiefe geht in der Hierarchie, desto mehr parallele Threads auf einem Level gibt es ja.

    Harzliche Grüße aus http://www.annerschbarrich.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau
    1. I.d.R. will man ja gar nicht den ganzen Baum auf einmal sehen, sondern immer nur eine Ebene zusätzlich einblenden oder wieder ausblenden. Dazu kann man sich einfach den Level mit abspeichern beim Anlegen des abhängigen Posts. Wenn man dann einen  Select über die Levels macht, hat man schon eine ganze Menge gewonnen. Ob meine Level-Spalte da nun stimmt, weiß ich nicht. Versuch mal, es zu überprüfen.

      Je weiter man in die Tiefe geht in der Hierarchie, desto mehr parallele Threads auf einem Level gibt es ja.

      Deine Level-Spalte ist korrekt (zeigt mir schonmal dass das Prinzip klar ist :)).
      Aber das hilft mir ja nur beim Anzeigen der Threads (wo ich bisher kein Problem hab), nicht aber beim Sortieren der Threadübersicht nach der letzten Antwort auf einen Thread.
      Vielleicht weisst ja auch dazu was :)

      greetz RFZ

  2. Huhu RFZ

    Verständlich? ;)

    Du möchtest also jeweils das letzte Posting ermitteln.
    Dann speicher einen Timestamp mit ab.

    Viele Grüße

    lulu

    --
    bythewaythewebsuxgoofflineandenjoytheday
    1. Du möchtest also jeweils das letzte Posting ermitteln.
      Dann speicher einen Timestamp mit ab.

      Das habe ich, kann ich aber auch anhand der id (da die ja stetig wächst).
      Ich will aber nicht das letzte Posting eines Thread einfach so ermitteln (das wär ja kein Problem: SELECT * FROM posts WHERE tid = 1 ORDER BY id DESC LIMIT 0,1)
      sondern will das in einem Zug beim auswählen der Threadübersicht machen.
      Also sowas wie: (SELECT *,id AS cid FROM posts WHERE pid = 0 AND SELECT id AS lastawid FROM posts WHERE tid = cid ORDER BY id DESC) ORDER BY lastawid DESC;
      Das wär jetz gedanklich das was ich vorhabe, Syntaktisch is das natürlich nicht korrekt ;)

      greetz RFZ

      1. Hello,

        ich habe vorhin verschweigen, dass es für solche Aufgaben speziell entwickelte Datenstrukturen gibt. Allerdings sind die schwer zu verstehen und schwer zu pflegen, aber schnell abzufragen. Jede Änderung daran kostet aber enorm viel Power.

        Man nennt die Dinger "nested sets"

        Findest Du bestimt sehr viel Informatives in Google.

        Ich halte die Teile aber für Anwendung in der Webwelt für weltfremd.

        Harzliche Grüße aus http://www.annerschbarrich.de

        Tom

        --
        Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
        Nur selber lernen macht schlau
        1. ich habe vorhin verschweigen, dass es für solche Aufgaben speziell entwickelte Datenstrukturen gibt. Allerdings sind die schwer zu verstehen und schwer zu pflegen, aber schnell abzufragen. Jede Änderung daran kostet aber enorm viel Power.
          Man nennt die Dinger "nested sets"

          Danke, aber so aussergewöhlich ist mein Vorhaben doch nun auch wieder nicht, oder? ;)
          Zur Not muss ich hald bei jedem Posten/löschen die lastawid in das Hauptposting als eigene Spalte eintragen, wär auch kein Drama ;)
          Wollt es nur eleganter lösen ;)

          1. Hello,

            ich habe vorhin verschweigen, dass es für solche Aufgaben speziell entwickelte Datenstrukturen gibt. Allerdings sind die schwer zu verstehen und schwer zu pflegen, aber schnell abzufragen. Jede Änderung daran kostet aber enorm viel Power.
            Man nennt die Dinger "nested sets"

            Danke, aber so aussergewöhlich ist mein Vorhaben doch nun auch wieder nicht, oder? ;)
            Zur Not muss ich hald bei jedem Posten/löschen die lastawid in das Hauptposting als eigene Spalte eintragen, wär auch kein Drama ;)
            Wollt es nur eleganter lösen ;)

            Eine nicht elegante aber sehr praktische Lösung liegt in der Begrenzung der Wertebereiche.

            Angenommen, du legst für jede Ebene maximal 99 Antworten fest, dann ergibt sich folgende einfache Möglichkeit:

            Threadnummer    bigint unsigned
            Antwort         VarChar(90)

            ergibt 30 Ebenen à 99 Antworten, macht maximal 2970 Postings in einem Thread.
            Aber Statiskik lässt sich leicht vergewaltigen. Besser, Du unterhältst Dich mal mit Christian Kruse, was hier im Forum so abgeht und wo bisher die Maxima lagen.

            tnr             childnr

            1               00.
            1               01.
            1               01.01.
            1               01.02.
            2               00.
            2               01.01.
            2               01.01.01.

            Da kann man dann beliebig intelligente Abfragen getalten und alles ist "linear"

            Harzliche Grüße aus http://www.annerschbarrich.de

            Tom

            --
            Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
            Nur selber lernen macht schlau
            1. Eine nicht elegante aber sehr praktische Lösung liegt in der Begrenzung der Wertebereiche.
              Angenommen, du legst für jede Ebene maximal 99 Antworten fest, dann ergibt sich folgende einfache Möglichkeit: (...)
              Da kann man dann beliebig intelligente Abfragen getalten und alles ist "linear"

              Ok, vielleicht hast du doch nicht ganz verstanden was ich eigentlich will ;)
              Du bist irgendwie immer auf die Ebenen aus, damit hat es aber überhaupt nichts zu tun...

              Ich möchte im Prinzip nichts anderes tun als zwei SELECT Anweisungen zu vereinen, es hat nichtmal mit der Forumstruktur was zu tun...

              greetz RFZ

              1. Hello,

                Ok, vielleicht hast du doch nicht ganz verstanden was ich eigentlich will ;)
                Du bist irgendwie immer auf die Ebenen aus, damit hat es aber überhaupt nichts zu tun...

                Ich möchte im Prinzip nichts anderes tun als zwei SELECT Anweisungen zu vereinen, es hat nichtmal mit der Forumstruktur was zu tun...

                Vielleicht liegt das auch an Deiner Beschreibung?
                Was heißt denn: "... die letzte ID des Postings wissen, dessen tid die id des Threads ist... "?

                Jedes Posting hat nur eine ID
                Jedes Posting _kann_ aber Kinder und Kindeskindre haben.
                Was ist nun das letzte Posteing zum Thread?

                • das in der Hierachie am tiefsten liegt?
                • das zeitlich das letze ist, aber in direkter Erbfolge des Threads liegt?
                • das direkt in der Ebene unter dem Thread liegt, aber zeitlich das letzte war?

                Vielleicht hat Du die mehdimensionalität Deiner eigenen Aufgabe noch nicht verstanden. Mit meiner Simpellösung aus meinem zur Zeit (zeitlich) letzten Posting auf Deinen Originalthread kannst Du alle o.a. Varianten erschlagen.

                Harzliche Grüße aus http://www.annerschbarrich.de

                Tom

                --
                Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                Nur selber lernen macht schlau
                1. Was ist nun das letzte Posteing zum Thread?

                  • das in der Hierachie am tiefsten liegt?
                  • das zeitlich das letze ist, aber in direkter Erbfolge des Threads liegt?
                  • das direkt in der Ebene unter dem Thread liegt, aber zeitlich das letzte war?

                  Das letzte Posting auf einen Thread ist das zeitlich letzte in irgendeiner Ebene eines Threads, also der Datensatz mit der größten id (je tid)

                  Beispiel für die Threadliste:
                  SELECT * FROM posts WHERE pid=0 ORDER BY id DESC LIMIT 0,10

                  Beispiel für das letzte POsting von Thread 1:
                  SELECT id FROM posts WHERE tid=1 ORDER BY id DESC LIMIT 0,1

                  So, und diese beiden SELECTs will ich einfach _in einem_ haben, sodass zu jedem Thread der Threadliste schon die letzte AntwortID ermittelt wird ;)

                  greetz RFZ

                  1. Hello,

                    Das letzte Posting auf einen Thread ist das zeitlich letzte in irgendeiner Ebene eines Threads, also der Datensatz mit der größten id (je tid)

                    So, und diese beiden SELECTs will ich einfach _in einem_ haben, sodass zu jedem Thread der Threadliste schon die letzte AntwortID ermittelt wird ;)

                    Dann schau Die meine Struktur nochmals an.
                    Aus der Praxis heraus erhält jede Struktur in tid die ID des Mutterthreads. Die ist also NICHT Unique. Damit kann man schon mal die ganze Familie greifen. Und nun kann man ind die Unterebenen einsteigen und beliebig filtern

                    alle der Kindfamile 01. fangen eben mit "01." an. Und von denen kann man dann auch das letzte finden, wenn man nun wiederum Lulus Vorschlag dazunimmt, und einen genügend feinen Timestamp setzt. Der sollte bei heutiger Technologie aber tatsächlich im Millisekundenbereich liegen, damit es keine Dubletten gibt.

                    Ein einfaches SQL-Statement auf einer mittleren Hardware eines mittelmäßig schnellen DBMS dauert nur noch max. ca. 8ms. Dann kann schon das nächste bearbeitet werden. Da wäre dann vielleicht usec doch besser, oder?

                    Harzliche Grüße aus http://www.annerschbarrich.de

                    Tom

                    --
                    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                    Nur selber lernen macht schlau
                    1. alle der Kindfamile 01. fangen eben mit "01." an. Und von denen kann man dann auch das letzte finden, wenn man nun wiederum Lulus Vorschlag dazunimmt, und einen genügend feinen Timestamp setzt. Der sollte bei heutiger Technologie aber tatsächlich im Millisekundenbereich liegen, damit es keine Dubletten gibt.

                      Das habe ich doch oben eben gemacht?!?

                      Beispiel für das letzte Posting von Thread 1:
                      SELECT id FROM posts WHERE tid=1 ORDER BY id DESC LIMIT 0,1

                      Dafür brauch ich keinen Timestamp oder deinen Vorschlag mit 01.02.03... Dieses SELECT liefert mir ja den letzten Beitrag eines Threads.
                      Das Problem ist, es muss gleichzeitig mit dem Abrufen der Threadliste passieren, nicht danach.

                      1. Hello,

                        alle der Kindfamile 01. fangen eben mit "01." an. Und von denen kann man dann auch das letzte finden, wenn man nun wiederum Lulus Vorschlag dazunimmt, und einen genügend feinen Timestamp setzt. Der sollte bei heutiger Technologie aber tatsächlich im Millisekundenbereich liegen, damit es keine Dubletten gibt.

                        Das habe ich doch oben eben gemacht?!?

                        Beispiel für das letzte Posting von Thread 1:
                        SELECT id FROM posts WHERE tid=1 ORDER BY id DESC LIMIT 0,1
                        Dafür brauch ich keinen Timestamp oder deinen Vorschlag mit 01.02.03... Dieses SELECT liefert mir ja den letzten Beitrag eines Threads.
                        Das Problem ist, es muss gleichzeitig mit dem Abrufen der Threadliste passieren, nicht danach.

                        Nun kommen wir der Sache schon näher. Dann kannst Du einen Selbstbezug oder ein Subselect aufbauen. Das ist nichts weiter Weltbewegendes. Schau mal in http://dev.mysql.com/doc/mysql/de/Legal_names.html

                        Du kannst eine Tabelle innerhalb eines Selects zweimal öffnen und dann mit sich selbst vergleichen.

                        Harzliche Grüße aus http://www.annerschbarrich.de

                        Tom

                        --
                        Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                        Nur selber lernen macht schlau
                        1. Hello,

                          Einen Timestamp wirst Du aber trotzdem benötigen, da viele SQL-DBMS keinen Autoincrement Key habe und diejenigen, die einen haben, oft nicht garantieren, dass der tatsächlich immer nur aufwärts zählt. Es könnte sein, dass das DBMS zwischendurch mal entscheidet, Lücken zu schließen.

                          Ich finde das zwar auch schofelig von so nem DBMS aber man steckt ja nicht drin...

                          Harzliche Grüße aus http://www.annerschbarrich.de

                          Tom

                          --
                          Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                          Nur selber lernen macht schlau
                        2. Nun kommen wir der Sache schon näher. Dann kannst Du einen Selbstbezug oder ein Subselect aufbauen. Das ist nichts weiter Weltbewegendes. Schau mal in http://dev.mysql.com/doc/mysql/de/Legal_names.html

                          Du kannst eine Tabelle innerhalb eines Selects zweimal öffnen und dann mit sich selbst vergleichen.

                          Darauf will ich hinaus, aber das hab ich auch schon früher gepostet ;)
                          Das Problem ist dass ich den richtigen Syntax einfach nicht gefunden habe, ich hoffe hald dass mir jemand hier ein Beispiel posten kann...

                          greetz RFZ

                          1. Hello,

                            Darauf will ich hinaus, aber das hab ich auch schon früher gepostet ;)
                            Das Problem ist dass ich den richtigen Syntax einfach nicht gefunden habe, ich hoffe hald dass mir jemand hier ein Beispiel posten kann...

                            Das kannst Du Dir ganz alleine bauen. Du bist ja nicht doof ;-)

                            Bau das eine Statement auf     Nenn die Tabelle a
                            Bau das andere Statement auf   Nenn die Tabelle b
                            verbinmde beide über die gemeinsame Eigenschaft mit einem where

                            Ich hatte hier neulich schon mal gepostet, wie man sowas darstellen kann, um nicht die Übersicht zu verleiren und nicht nachher doch ein karthesisisches Produkt beider Abfragen zu bekommen. Das würde das System ggf. zum Stehen bringen.

                            SELECT a.id, a.parentid, a.sort
                            from test_productmodels a, test_productmodels b
                            WHERE a.parentid = b.parentid AND a.sort <= b.sort AND b.id = '2'
                            ORDER BY parentid, sort DESC
                            LIMIT 0 , 2

                            Das ist ein Beispiel, bei dem anhand einer ID deren Parent-ID gesucht wird, um dann die zwei Datensätze der Parent-ID zu finden, die in der Sortierung (sort) aufeinanderfolgen. Hier wird der Vorgänger des Satzes mit der ID 2 gesucht.

                            So ähnlich musst Du Dein Statement dann auch bauen.

                            Harzliche Grüße aus http://www.annerschbarrich.de

                            Tom

                            --
                            Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                            Nur selber lernen macht schlau
                            1. SELECT a.id, a.parentid, a.sort
                              from test_productmodels a, test_productmodels b
                              WHERE a.parentid = b.parentid AND a.sort <= b.sort AND b.id = '2'
                              ORDER BY parentid, sort DESC
                              LIMIT 0 , 2

                              Damit komm ich dann etwa auf sowas:

                              SELECT a.*, b.id AS lawid FROM posts a, posts b WHERE a.pid = 0 AND b.tid=a.id AND b.id = MAX(b.id) ORDER BY lawid DESC

                              Aber das geht nicht (Falsche Verwendung der GROUP-Funktion)

                              Kannst mir nicht sagen wie es lauten muss, falls es überhaupt so geht?

                              1. Hello,

                                SELECT a.id, a.parentid, a.sort
                                from test_productmodels a, test_productmodels b
                                WHERE a.parentid = b.parentid AND a.sort <= b.sort AND b.id = '2'
                                ORDER BY parentid, sort DESC
                                LIMIT 0 , 2

                                Damit komm ich dann etwa auf sowas:

                                SELECT a.*, b.id AS lawid FROM posts a, posts b WHERE a.pid = 0 AND b.tid=a.id AND b.id = MAX(b.id) ORDER BY lawid DESC

                                Aber das geht nicht (Falsche Verwendung der GROUP-Funktion)

                                Ja, genau einmal darfst Du raten, warum ich Limit benutzt habe.

                                Max() darf in MySQL nur ohne Group by verwendet werden, wenn nur EIN aggregiertes Ergebnis herauskommt. Du willst ja aber zwei Ergebnisdatensätze haben, die nicht beide MXA sind, sondern nur einer davon.

                                Harzliche Grüße aus http://www.annerschbarrich.de

                                Tom

                                --
                                Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                                Nur selber lernen macht schlau
                                1. Ja, genau einmal darfst Du raten, warum ich Limit benutzt habe.

                                  Max() darf in MySQL nur ohne Group by verwendet werden, wenn nur EIN aggregiertes Ergebnis herauskommt. Du willst ja aber zwei Ergebnisdatensätze haben, die nicht beide MXA sind, sondern nur einer davon.

                                  Ich will zwei Datensätze? Nein, ich will alle Threads haben (pid=0)...
                                  Ich hab von GROUP BY keine Ahnung und heut schon den ganzen Tag das MySQL Manual studiert... Kannst nicht mein query oben so umschreiben dass es geht?

                                  greetz RFZ

                                2. Ok, habs:

                                  SELECT a.*, MAX(b.id) AS lawid FROM posts a, posts b WHERE a.parentid=0 AND b.threadid=a.id GROUP BY id ORDER BY lawid DESC;

                                  Hat ja lang genug gedauert.... ;)

                                  greetz RFZ

                                  1. Hello,

                                    Ok, habs:

                                    SELECT             a.*,                      MAX(b.id) AS lawid
                                    FROM               posts a,                  posts b
                                    WHERE              a.parentid=0
                                    AND                a.id              =       b.threadid

                                    GROUP BY id                          ## da gabs kein Gemecker?
                                                                ORDER BY lawid DESC;

                                    So wäre meine Schreibweie im "T-Modell des Buchhalters"

                                    Das muss ich mir auch mindestens noch dreizehnmal anschauen. Ích habs nämlich eben nicht hinbekommen.

                                    Harzliche Grüße aus http://www.annerschbarrich.de

                                    Tom

                                    --
                                    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                                    Nur selber lernen macht schlau
    2. Hello lulu,

      Du möchtest also jeweils das letzte Posting ermitteln.
      Dann speicher einen Timestamp mit ab.

      Ein Timestamp hat beo Hierarchisch gegliederten Strukturen, die sich wie diese, durch parallele Äste auszichnen, die wiederum in keinem zeitlichen Zusammenhang stehen, nicht viel Sinn. Es gibt sicherlich in verschiednen Threads gleiche Timestamps. Die haben aber nichts miteinander zu tun.

      Harzliche Grüße aus http://www.annerschbarrich.de

      Tom

      --
      Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
      Nur selber lernen macht schlau