Announcement

Collapse
No announcement yet.

Schleifen in SQL Abfrage: Expertenwissen gefragt

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Schleifen in SQL Abfrage: Expertenwissen gefragt

    Hallo zusammen,

    ich habe in den letzten Tagen einige grössere Berechnungen durchführen müssen und bin dabei immer wieder auf folgendes Problem gestossen, welches ich trotz Nachfragen bei unserem Freund "Google" nicht wirklich lösen konnte.

    In vereinfachter Weise möchte ich das Problem kurz schildern:
    Es existiert eine Tabelle mit (unter anderem folgenden) Spalten:
    - UserID (Jeder Nutzer einer Website hat eine eindeutige ID)
    - BeitragID (jeder Newsflashbeitrag auf der Webseite hat eine eindeutige ID)
    - Publikationsdatum des Beitrags
    - Click-Time: Wann hat der User die entsprechende Ressource abgefragt
    ...

    Die Spalte BeitragID ist für dieses Problem erst mal nicht relevant. Die Aufgabe besteht darin Clickstreams pro User und Publikationstagen zu berechnen. Ein Clickstream umfasst daher (nach dieser Definition nur Newsbeiträge eines Publikationstages, die Fragestellung erfordert dies - soll hier nicht weiter hinterfragt werden). Weiter gilt jedes Mal, wenn die Zeit zur vorangehenden Newsartikelabfrage > 10min ist als neuer Stream. Damit gibt es innerhalb jeder User & Publikationsdatum kombination möglicherweise mehrere Clickstreams.

    Ich habe nun in Java ein Programm geschrieben, welches mir für jeden User und jeden Publikationstag eine Tabelle zurückgibt, auf welche anschliessend eine Funktion angewendet wird, um die User & Beitrag-Kombinationen einem Clickstream zuzuordnen. Diese Funktion trägt anschliessend in der Ursprungstabelle zwei neue Spaltenwerte ein (pro Entität):
    - Anfang (=1=/ In der Mitte (=2)/ Ende eines Klickstreams (=3)
    - Jeder Clickstream bekommt eine eindeutige ID zugeordnet, d.h. jede Entität bekommt also eine Clickstream-Nummer (ein Clickstream kann mehrere Newsflash&Userkombinationen umfassen). Dies erfordert also einige Vergleiche (Zeit oberhalb, Zeit unterhalb etc...)

    Die veränderte Tabelle sieht dann so aus:
    - UserID (Jeder Nutzer einer Website hat eine eindeutige ID)
    - BeitragID (jeder Newsflashbeitrag auf der Webseite hat eine eindeutige ID)
    - Publikationsdatum des Beitrags
    - Click-Time: Wann hat der User die entsprechende Ressource abgefragt
    - Anfang / Inside / Ende des Clickstreams
    - Eindeutige Nummer für jeden Clickstream


    Das Programm funktioniert, nur liegt das grosse Problem darin, dass die Tabelle sehr gross ist (über 140 000 Einträge) und die Ausführung zirka 10 Stunden dauert. Ist leider nicht wirklich akzeptabel so, da ich diesen Vorgang relativ häufig wiederholen muss. Verglichen mit normalen SQL Abfragen direkt im Microsoft SQL Server (welche maximal einige Sekunden dauern) dauert der Umweg über das Java-Programm unglaublich lang.

    Daher meine Frage:

    - Gibt es eine Möglichkeit solche Abfragen in MS SQL zu programmieren?
    for (UserID, min BIS UserID, max) {
    for(Publikationstag, min BIS Publikationstag, max) {
    --Gib mir die Tabelle zurück, die genau der UserID und dem Publikationstag entspricht und führe darauf Berechnungen durch und speichere diese in der Ursprungstabelle)
    }
    }


    Denke, dass solche dynamische Abfragen in der Realität relativ häufig zum Einsatz kommen, und kann mir nicht vorstellen, dass es keinen besseren Weg gibt....

    ????

    Über eine Hilfestellung würde ich mich sehr freuen.

    Vielen Dank
    Barbara

  • #2
    Hallo Barbara,

    oh ha, so viel Text am Montag zum Lesen; ob ich das alles richtig verstanden habe ...

    "dass die Tabelle sehr gross ist (über 140 000 Einträge)" na,ja, das ist noch nicht wirklich viel...

    Also,
    1. Schleifen / Cursor (Server-Round-Trips) sind immer inperformant, das sollte man immer vermeiden.
    2. Ich helfe mir immer damit, das ich das Problem so einfach wie möglich zu beschreiben, so als wollte man es einem Kleinkind erklären (also mir oder dem MSSQL)

    In Deinem Fall könnte man es so formulieren:

    - "Anfang" ist jeder Datensatz, der keinen Vorgänger älter als 10 Minuten hat
    - "Ende" ist jeder Datensatz, der keinen Nachfolger älter als 10 Minuten hat
    - "Inside" sind damit alle anderen

    Und wenn das von der Logik her passt, kannst Du es fasst "mengenorientiert" abhandeln und auf Schleifen verzichten:
    [highlight=SQL]
    UPDATE Tabelle
    SET ClickPart = 1, -- Anfang
    ClickID = NEWID()
    WHERE NOT EXISTS(SELECT 1
    FROM Tabelle AS SUB
    WHERE SUB.UserID = Tabelle.UserID
    AND SUB.Publikationsdatum = Tabelle.Publikationsdatum
    AND SUB.ClickTime >= DATEADD(mi, -10, Tabelle.Tabelle.Publikationsdatum)

    UPDATE Tabelle
    SET ClickPart = 3, -- Ende
    ClickID = (SELECT TOP 1 ClickID FROM Tabelle AS SUB
    WHERE SUB.UserID = Tabelle.UserID
    AND SUB.Publikationsdatum = Tabelle.Publikationsdatum
    AND NOT ClickID IS NULL
    AND AND SUB.ClickTime <= Tabelle.ClickTime
    AND ClickPart = 1
    ORDER BY SUB.ClickTime DESC)
    WHERE NOT EXISTS(SELECT 1
    FROM Tabelle AS SUB
    WHERE SUB.UserID = Tabelle.UserID
    AND SUB.Publikationsdatum = Tabelle.Publikationsdatum
    AND SUB.ClickTime <= DATEADD(mi, 10, Tabelle.Tabelle.Publikationsdatum)

    UPDATE Tabelle
    SET ClickPart = 2, -- Inside
    ClickID = (SELECT TOP 1 ClickID FROM Tabelle AS SUB
    WHERE SUB.UserID = Tabelle.UserID
    AND SUB.Publikationsdatum = Tabelle.Publikationsdatum
    AND NOT ClickID IS NULL
    AND AND SUB.ClickTime <= Tabelle.ClickTime
    AND ClickPart = 1
    ORDER BY SUB.ClickTime DESC)

    WHERE ClickPart IS NULL
    [/highlight]

    Ist nicht getestet, aber so in der Art müsste es gehen.

    Das kann man natürlich noch optimieren, SubSelect sind unter MSSQL auch nicht das schnellst.

    Wo bekommst Du die eindeutige Nummer je Clickstream her bzw. wie willst Du die generieren?
    Was ist mit Sätzen über Mitternacht hinweg, sollen die speziell berücksichtigt werden? (Also 1 Minute vor + nach Mitternacht gehört zu einem Stream)?
    Olaf Helper

    <Blog> <Xing>
    * cogito ergo sum * errare humanum est * quote erat demonstrandum *
    Wenn ich denke, ist das ein Fehler und das beweise ich täglich

    Comment


    • #3
      Hallo Olaf,

      Danke schon mals für deine Antwort - ich kann die grobe Vorgehensweise nachvollziehen, verstehe den Code jedoch noch nicht vollständig und konnte ihn daher auch nicht an mein Beispiel anpassen (arbeite erst seit wenigen Tagen mit MS SQL). Ich habe jetzt mal ein Beispiel vorbereitet (.bak-Datei in einem zip-verpackt). Die Datei ist allerdings zu gross um hier anzuhängen, sie ist unter folgendem Link zu erreichen:

      http://www.file-upload.net/download-...mTest.zip.html


      Sie beinhaltet jetzt bereits die beiden neu zu erstellenden Spalten (ClickCode und ClickStreamID):
      - Clickcode: 1 = Anfang, 2 = Inside, 3 = Ende;
      dazu habe ich noch einen Code 4 verwendet, welcher im Prinzip einer 1 gleichkommt, aber angibt, dass der User von dem entsprechenden Publikationsdatum bereits zuvor einen Clickstream durchgeführt hatte (brauche ich für die Auswertung ebenfalls). Im Prinzip muss noch ein Code 5 folgen, welcher den Spezialfall beinhaltet, dass Anfang = Ende ist, d.h. in einem Clickstream nur genau eine Ressource abgefragt wurde.
      Aber möglicherweise lassen wir diese beiden Fälle im ersten einfachen Beispiel mal weg...

      Beispiel aus dem File:
      - User 4094 liest nur Artikel vom 23.05.08 und nur genau an diesem Tag. Allerdings macht er zweimal eine längere Pause (grösser 10minuten), so dass wir drei verschiedene Clickstreams für ihn identifizieren. Es gibt dreim mal ein Endcode (=3) und im Prinzip auch drei Anfangscode (einmal eine 1, zweimal eine 4). Er beginnt nur einmal das erste Mal Artikel vom 23.05. zu lesen (Code 1), jedoch zweimal steigt er anschliessend wieder ein (Code 4).
      - User 6777 hat zwei Clickstreams. Einmal beginnt er Artikel vom 23.05. am 23.05. zu lesen (1) und schliesst diesen Stream auch wieder ab (3), einmal am am 27.05. (Code 4) und schliesst diesen natürlich auch wieder ab (3).

      Die eindeutigen ClickstreamIDs müssen aufgrund der Codes erzeugt werden, d.h.
      - globalen Zähler
      - sortiere die ganze Tabelle zuerst nach userid, anschliessend nach publikationstag und schliesslich nach der Clicktime. Dann gehe die Spalte ClickCode von oben nach unten durch und setze jedes mal, wenn eine 3 kommt den globalen Zähler nach oben. Füge für jede Entität den globalen Zähler ein... (vereinfachte beschreibung)....

      Hoffe, dass die Problemstellung jetzt etwas klarer ist und ich irgendwie durch die Forumshilfe an eine Lösung komme.
      Vielen herzlichen Dank
      Barbara

      Comment


      • #4
        Hallo Barbara,

        wie sieht es mit dem 2. Datensatz
        4094 / 23.05.2008 08:45:50
        Der ist bei Dir mit 2 codiert, meines dafürhalten nach ist es eine 4; allerdings gibt dann keinen "Inside" Datensatz?

        Kann man Dich dazu überreden, ein Feld mit einer IDENTITY ID einzubauen? Das würde es etwas einfacher machen.
        Olaf Helper

        <Blog> <Xing>
        * cogito ergo sum * errare humanum est * quote erat demonstrandum *
        Wenn ich denke, ist das ein Fehler und das beweise ich täglich

        Comment


        • #5
          hallo olaf.

          stimmt, sorry - da hatten wir noch eine andere definition von clickstreams - da war es noch eingestellt "wenn grösser 15minuten" anstelle von "wenn grösser 10min".

          ja, wenn es hilft, könnte man die identity id einbauen. allerdings müsste es im nachhinein möglich sein - denn ich bekomme den datensatz genau so wie er ist... ;-)
          aber denke, dass man eine identity id im nachhinein einbauen könnte, oder?

          gruss
          b

          Comment


          • #6
            Also, abgesehen von Tippfehlern und kleinen Logikfehlern (nur ganz kleine ;-) passt mein erster Entwurf.

            Ich habe mal 2 Felder für das Ergebnis hinzugefügt, damit Du meins/Deins vergleichen kannst.
            Ausserdem ein Id Fehler, weil es die Angelegenheit vereinfach.

            Was noch fehlt, ist die Ermittlung der "clickstreamid", ein bisschen Arbeit soll für Dich ja auch über bleiben.

            [highlight=SQL]
            -- Tabelle um ID erweitern
            ALTER TABLE dbo.test ADD
            clickcode_oh smallint NULL,
            clickstreamid_oh int NULL,
            id int NOT NULL IDENTITY (1, 1)
            GO

            -- ************************************************** *********
            -- Der jüngste Eintrag pro Tag ist
            -- immer 1 - Anfang
            UPDATE test
            SET clickcode_oh = 1,
            clickstreamid_oh = clickstreamid -- Gefaket: Hier fehlt noch die ID Ermittelung
            WHERE clickcode_oh IS NULL
            AND id IN (SELECT MIN(id)
            FROM test
            GROUP BY userid, publikationsdatum)
            GO

            -- 4 - "Anfang" ist jeder Datensatz, der keinen Vorgänger älter als 10 Minuten hat
            UPDATE test
            SET clickcode_oh = 4,
            clickstreamid_oh = clickstreamid -- Gefaket: Hier fehlt noch die ID Ermittelung
            WHERE clickcode_oh IS NULL
            AND NOT EXISTS(SELECT SUB.id
            FROM test AS SUB
            WHERE SUB.id <> test.id
            AND SUB.userid = test.userid
            AND SUB.publikationsdatum = test.publikationsdatum
            AND SUB.ClickTime >= DATEADD(mi, -10, test.clicktime)
            AND SUB.ClickTime < test.clicktime)
            GO

            -- 3 - "Ende" ist jeder Datensatz, der keinen Nachfolger jünger als 10 Minuten hat
            UPDATE test
            SET clickcode_oh = 3,
            clickstreamid_oh = (SELECT TOP 1 clickstreamid_OH
            FROM test AS SUB
            WHERE SUB.UserID = test.UserID
            AND SUB.Publikationsdatum = test.Publikationsdatum
            AND NOT clickstreamid_OH IS NULL
            AND SUB.ClickTime <= test.ClickTime
            AND clickcode_oh IN (1, 4)
            ORDER BY SUB.ClickTime DESC)
            WHERE clickcode_oh IS NULL
            AND NOT EXISTS(SELECT SUB.id
            FROM test AS SUB
            WHERE SUB.id <> test.id
            AND SUB.userid = test.userid
            AND SUB.publikationsdatum = test.publikationsdatum
            AND SUB.ClickTime <= DATEADD(mi, 10, test.clicktime)
            AND SUB.ClickTime > test.clicktime)
            GO

            -- 2 - Inside ist der gesamte Rest, der noch keinen Code hat
            UPDATE test
            SET clickcode_oh = 2,
            clickstreamid_oh = (SELECT TOP 1 clickstreamid_OH
            FROM test AS SUB
            WHERE SUB.UserID = test.UserID
            AND SUB.Publikationsdatum = test.Publikationsdatum
            AND NOT clickstreamid_OH IS NULL
            AND SUB.ClickTime <= test.ClickTime
            AND clickcode_oh IN (1, 4)
            ORDER BY SUB.ClickTime DESC)
            WHERE clickcode_oh IS NULL
            GO
            [/highlight]
            Olaf Helper

            <Blog> <Xing>
            * cogito ergo sum * errare humanum est * quote erat demonstrandum *
            Wenn ich denke, ist das ein Fehler und das beweise ich täglich

            Comment


            • #7
              Danke, danke Olaf - sieht schon sehr gut aus. Ich muss gleich weg - werde den Code aber heute Abend/Nacht dann intensiv ausprobieren und melde mich anschliessend wieder...

              Gruss Barbara

              Comment


              • #8
                Hallo Olaf,

                ich bin begeistert. Dein Code funktioniert einwandfrei und verglichen mit den Loops in Java ist er unglaublich schnell (15 sekunden).

                Ich habe jetzt noch den Spezialfall eingebaut, dass nur ein Eintrag pro Clickstream existiert und ihm den Code 5 verteilt.

                Dieser Code wird vor dem Code für Code1 ausgeführt:

                Code:
                      -- ***********************************************************
                   
                      -- Wenn nur genau 1 Eintrag im Clickstream: d.h. Anfang = Ende
                 
                      -- 5
                 
                      UPDATE test
                 
                      SET clickcode_oh = 5
                 
                      WHERE clickcode_oh IS NULL
                 
                            AND id IN (SELECT MIN(id)
                 
                                     FROM test
                 
                                       GROUP BY userid, publikationsdatum)
                		
                			AND id IN (SELECT MAX(id)
                 
                                     FROM test
                 
                                       GROUP BY userid, publikationsdatum)
                     GO

                Auf Code3 folgt dann nochmals:

                Code:
                      -- 5 - ist jeder Datensatz, der keinen Vorgänger älter als 10 Minuten und keinen Nachfolger älter als 10 Minuten hat
                	
                	  -- Wenn nur genau 1 Eintrag im Lesevorgang: d.h. Anfang = Ende
                 
                      -- 5 
                
                      UPDATE tresultsextendedolaf
                 
                      SET clickcode_oh = 5
                 
                      WHERE clickcode_oh IS NULL
                 
                            AND NOT EXISTS(SELECT SUB.id
                 
                                           FROM tresultsextendedolaf AS SUB
                 
                                          WHERE SUB.id <> tresultsextendedolaf.id
                 
                                                 AND SUB.userid = tresultsextendedolaf.userid
                 
                                                 AND SUB.publikationsdatum  = test.publikationsdatum
                 
                                                 AND SUB.Clicktime >= DATEADD(mi, -10, test.clicktime)
                 
                                                 AND SUB.Clicktime < test.clicktime)
                			
                			AND NOT  EXISTS(SELECT SUB.id
                 
                                            FROM test AS SUB
                 
                                            WHERE SUB.id <> test.id
                 
                                                  AND SUB.userid = test.userid
                 
                                                  AND SUB.publikationsdatum  = test.publikationsdatum
                 
                                                  AND SUB.Clicktime <= DATEADD(mi, 10, test.clicktime)
                 
                                                  AND SUB.Clicktime > test.clicktime)
                 
                 
                      GO
                Glaube, dass dies so stimmt, oder?

                Ein Problem hatte ich jedoch noch: Meine Ursprungstabelle war nicht nach den entsprechenden Felder sortiert (Userid, Datum, Clicktime). Daher waren die Codes zu Beginn dann natürlich auch nicht korrekt. Ich habe dies dann so gelöst, dass ich eine Abfrage mit der entsprechenden Sortierung in einer neuen Tabelle eingefügt habe. Funktioniert - aber gibt es eine Möglichkeit die Sortierung in der selben Tabelle vorzunehmen?

                Gibt es im Internet weitere Beispiele zur "mengenorientierten" Abfrage? Oder ein gutes Buch? Denke nämlich, dass ich diese Art der Abfrage in Zukunft noch brauchen werde und würde daher gerne selber die Gedankengänge erlernen. Kann den Code zwar knapp nachvollziehen, denke aber nicht, dass ich selber ohne Weiteres auf diese Lösung gekommen wäre.

                Um die Clickstream IDs zu erzeugen: kann ich da einen Cursor einsetzen? Der muss ja im Prinzip nur von oben nach unten die clickcode_oh-Spalte passieren und jeweils den Zähler um 1 erhöhen, wenn entweder ein Code 3 oder 5 folgt und dann in der spalte stream-id die entsprechende zahl eintragen. Oder gibt es hier auch einen mengenorientierten Ansatz, der geeigneter ist?


                Olaf, besten Dank nochmals - deine Hilfe weiss ich echt zu schätzen.
                Viele Grüsse
                Barbara
                Zuletzt editiert von barbara83; 08.07.2008, 04:01.

                Comment


                • #9
                  ich habe jetzt mal versucht die clickstream_id's in die tabelle einzutragen mit folgendem cursor:

                  Code:
                  Declare @clickstreamid_zeiger int
                  
                  SET @clickstreamid_zeiger = 1
                  
                  
                  --Cursor
                  DECLARE navigator CURSOR LOCAL SCROLL KEYSET
                  FOR
                  	SELECT clickcode_oh, clickstreamid_oh, id FROM tabelle
                  FOR UPDATE
                  
                  OPEN navigator
                  
                  DECLARE @code int, @clickstreamid int, @id int
                  
                  FETCH NEXT FROM navigator INTO @code, @clickstreamid, @id
                  
                  WHILE @@fetch_status = 0
                  	BEGIN
                  		UPDATE tabelle SET clickstreamid_oh = @clickstreamid_zeiger where id = @id		
                  		IF (@code = 3 OR @code = 5) 
                  			BEGIN
                  				SET @clickstreamid_zeiger = @clickstreamid_zeiger + 1
                  			END
                  		
                  		FETCH NEXT FROM navigator INTO @code, @clickstreamid, @id
                  	END
                  
                  CLOSE navigator
                  DEALLOCATE navigator
                  Funktioniert - nur dauert es wiederum mehere stunden die id's einzutragen. (kurze zwischenfrage aus reinem interesse: mein notebook ist 4 jahre alt - aber auch auf einem neueren computer würde diese operation nicht viel schneller von statten gehen, oder?)

                  versuche mal einen mengenorientieren ansatz - aber bin mir nicht sicher, ob ich diese denkweise bereits aufnehmen konnte...



                  liebe grüsse

                  Comment


                  • #10
                    Nachtrag:

                    Mit dieser kleinen Änderung funktioniert es jetzt schon recht flott.... damit diese ausführung aber möglich ist, muss die tabelle einen primärschlüssel besitzen....

                    ist wahrscheinlich nicht die schönste und schnellste variante, funktioniert aber insgesamt in erduldbarer zeit.


                    Code:
                    Declare @clickstreamid_zeiger int
                    
                    SET @clickstreamid_zeiger = 1
                    
                    
                    --Cursor
                    DECLARE navigator CURSOR LOCAL SCROLL KEYSET
                    FOR
                    	SELECT clickcode_oh, clickstreamid_oh, id FROM tabelle
                    FOR UPDATE
                    
                    OPEN navigator
                    
                    DECLARE @code int, @clickstreamid int, @id int
                    
                    FETCH NEXT FROM navigator INTO @code, @clickstreamid, @id
                    
                    WHILE @@fetch_status = 0
                    	BEGIN
                    		UPDATE tabelle SET clickstreamid_oh = @clickstreamid_zeiger WHERE CURRENT OF navigator		
                    		IF (@code = 3 OR @code = 5) 
                    			BEGIN
                    				SET @clickstreamid_zeiger = @clickstreamid_zeiger + 1
                    			END
                    		
                    		FETCH NEXT FROM navigator INTO @code, @clickstreamid, @id
                    	END
                    
                    CLOSE navigator
                    DEALLOCATE navigator

                    Comment


                    • #11
                      Hallo Barbara,

                      zu welchen Uhrzeiten postest denn Du? Um die Zeiten liege ich im Bett und schlafe ;-)

                      Wie man das elegant mit der clickstreamid lösen kann, weiß ich auch noch nicht, da werde ich mir noch Gedanken machen.
                      Bei eine mengenorientierte Lösung ist das Problem, das UPDATE keine Sortierung unterstützt.

                      Ist den eine lücklose, der Sortierung entsprechend vergeben ID unbedingt nötig?
                      Denn Sortieren kannst Du es zu jedem Zeitpunkt ja auf eine reproduzierbare Weise und eine Id wird ja meistens nur zum Identifizieren von Datensätze benötigt.

                      Bei Deinem Cursor oben musst Du auch
                      - entweder zuvor alle Datensätze wieder zurücksetzen
                      - oder die zuletzt verwendete (höchste) Id ermitteln und mit der weiterechnen.
                      Olaf Helper

                      <Blog> <Xing>
                      * cogito ergo sum * errare humanum est * quote erat demonstrandum *
                      Wenn ich denke, ist das ein Fehler und das beweise ich täglich

                      Comment


                      • #12
                        Ich noch mal ...

                        Dein Cursor ist übrigens nicht sortiert.

                        Nächster Versuch zum Thema ID.
                        Problem beim UPDATE ist wie erwähnt, das man keine Sortierung angeben kann.

                        Zudem ist es etwas lässtig, selbst eine Sequenz zu verwalten und die gewünschte Sortierung nach User, datum, clicktime macht es auch nicht einfacher.

                        Wann werden den die Ids vergeben? Den dadurch das die erste Sortierung der User ist, kommen abhängig vom Startpunkt unterscheidliche Ergebnisse heraus.

                        Hier mal meine Idee:

                        Um eine fortlaufende Id zu bekommen, bietet sich ein Zähler an (welch Erkenntnis ;-).

                        Also zähle ich alle Start ClickStreams Vorkommen, die in der Sortierung vor mir kommen; das ist dann "meine" Id für den jeweiligen Datensatz.
                        Wie in Deiner Bsp.Db beginnen die mit 1000, da kann man aber jeden anderen Wert auch angeben.

                        Hier das Sql dazu; das muss ausgeführt werden, nachdem alle Start Clickstreams gesetzt sind und bevor "Inside" und "Ende" gesetzt werden, da die die Id ja übernehmen.

                        Ich hatte zwar nur ein paar Daten zum Test, sollte aber gehen, auch wenn bereits zuvor Ids gesetzt wurden.
                        Allerdings nur bis zum (abgeschlossenen) Vortrag, sonst gibt es wegen userid als erste Sortierung fehlerhafte Werte (besser wäre Sortierung nach Tag, Uhrzeit, User).

                        [highlight=SQL]
                        -- Generieren der IDs für alle Starts der ClickStreams
                        UPDATE test
                        SET clickstreamid_oh = 1000 + ISNULL(
                        (SELECT COUNT(*)
                        FROM test AS SUB
                        WHERE clickcode_oh IN (1, 4, 5)
                        AND ((SUB.userid < test.userid) -- Erste Sort=userid
                        OR (SUB.userid = test.userid -- Zweite Sort= datum
                        AND SUB.publikationsdatum < test.publikationsdatum)
                        OR (SUB.userid = test.userid -- Dritte Sort= time
                        AND SUB.publikationsdatum = test.publikationsdatum
                        AND SUB.clicktime < test.clicktime)
                        )), 0)
                        WHERE clickstreamid_oh IS NULL
                        AND clickcode_oh IN (1, 4, 5)
                        -- Nur bis zum Vortag, sonst gibt es fehlerhafte Ergebnisse
                        AND publikationsdatum <= CONVERT(varchar(10), DATEADD(dd, -1, GETDATE()), 120)[/highlight]
                        Olaf Helper

                        <Blog> <Xing>
                        * cogito ergo sum * errare humanum est * quote erat demonstrandum *
                        Wenn ich denke, ist das ein Fehler und das beweise ich täglich

                        Comment


                        • #13
                          hallo olaf,

                          danke nochmals für deinen input.

                          mein cursor ist zwar nicht sortiert, aber wie in einem früheren posting erläutert, habe ich die ganze datenbank nach user, datum, clicktime sortiert. daher sollte die gewünschte ordnung trotzdem vorhanden sein. der cursor-ansatz scheint eigentlich zu funktionieren, ich konnte jedenfalls keinen fehler erkennen (stichprobenartiger test) - und die max(id) entspricht auch fast der anzahl 1 + 4 + 5, also im prinzip der anzahl clickstreams. eigentlich müssten ja die anzahl beginne (1 + 4) gleich gross sein wie die abschlüsse (3). allerdings weicht dies um 2 ab, d.h. auf 5000 clickstreams habe ich 2 fehler - verkraftbar, muss irgendein sonderfall sein, welchen wir bei den codes noch nicht berücksichtigt haben.

                          nochmals kurz eine unbeantwortete frage: kann ich eine tabelle sortieren (nach userid, datum, clicktime) und die sortierte tabelle dann anschliessend in der ursprünglichen tabelle abspeichern (quasi überschreiben) oder muss ich da immer eine neue tabelle erstellen?

                          probiere jetzt noch deinen clickstream_id-Ansatz aus..

                          gruss
                          barbara

                          Comment


                          • #14
                            Ich weiß nicht, ob ich Deine unbeantwortete Frage richtig verstehe.

                            Eigentlich ist eine Tabelle in dem Sinn nie sortiert, die Daten kommen halt so rein wie sie kommen.

                            Wo man eine Sortierung angeben kann, ist
                            - bei den Indizes
                            - beim SELECT auf die Tabelle
                            Sortiert zurückschreiben macht somit keinen Sinn.

                            Wenn Du die Werte der Tabelle sortiert als Liste haben willst, gib es beim Select an.

                            SELECT *
                            FROM test
                            ORDER BY userid, publikationsdatum, clicktime
                            Olaf Helper

                            <Blog> <Xing>
                            * cogito ergo sum * errare humanum est * quote erat demonstrandum *
                            Wenn ich denke, ist das ein Fehler und das beweise ich täglich

                            Comment

                            Working...
                            X