none
Cursor - Inhalt eine Spalte ändern RRS feed

  • Frage

  • Hallo zusammen,

    DECLARE cur CURSOR FOR

    SELECT row1, row2 FROM tab1;

    OPEN cur;

    FETCH NEXT FROM cur

    INTO @row1, @row2;

    WHILE @@FETCH_STATUS = 0

    BEGIN

    END

    Ich möchte in row2 Inhat auslesen und mit z.B. String "ddd" verketten und in row2 zurück schreiben.

    Ist das machbar? Oder wird der Tabelle tab1 durch Cursor gesperrt und lässt keine INSERT zu?

    Danke.

    Mittwoch, 25. Mai 2011 10:13

Antworten

  • andrej75 wrote:

    DECLARE cur CURSOR FOR
    SELECT row1, row2 FROM tab1;
    OPEN cur;
    FETCH NEXT FROM cur
    INTO @row1, @row2;
    WHILE @@FETCH_STATUS = 0 BEGIN

     UPDATE tab1 SET @row2 = @row1 + 'ddd'
       WHERE CURRENT OF cur

    END

    Ich möchte in row2 Inhat auslesen und mit z.B. String "ddd" verketten und
    in row2 zurück schreiben.

    HTH
    Henry

    • Als Antwort markiert andrej75 Mittwoch, 25. Mai 2011 12:28
    Mittwoch, 25. Mai 2011 11:21
  • Dich um etwas zu bitten, gestaltet sich wirklich schwierig ....

    Also, mittels der ROW_NUMBER() Funktion kann man je Datensatz eine laufende Nummer erzeugen, also 1 - n; über die ORDER BY Klausel kannst Du festlegen, wie die Reihenfolge ist (um so vorherige / nachfolgend festzulegen), hier eben row1.

    Dann definierst Du eine @start Wert und addierst dann mit DATEADD immer 5 min * die laufende Nummer auf; sieht da so aus:

    CREATE TABLE #tbl

        (row1 int, row2 smalldatetime);

     

    INSERT INTO #tbl (row1) VALUES (1);

    INSERT INTO #tbl (row1) VALUES (2);

    INSERT INTO #tbl (row1) VALUES (3);

    INSERT INTO #tbl (row1) VALUES (4);

    INSERT INTO #tbl (row1) VALUES (5);

    GO

     

    DECLARE @start smalldatetime;

    SET @start = {ts N'2011-01-01 12:00:00.000'}

     

    ;WITH cte AS

       (SELECT *, row_number() over (order by row1) - 1 AS LfdNr

        FROM #tbl)

    UPDATE cte

    SET row2 = DATEADD(mi, LfdNr * 5, @start)

     

    SELECT *

    FROM #tbl;

     

    GO

    DROP TABLE #tbl;

     


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



    • Als Antwort markiert andrej75 Mittwoch, 25. Mai 2011 12:28
    Mittwoch, 25. Mai 2011 12:05

Alle Antworten

  • Hallo Andrej,

    für so ein einfaches UPDATE ist doch kein Cursor nötig; einfach nur ein Update:

    UPDATE tab1

    SET row2 = row2 + 'ddd'

     


    Olaf Helper
    * cogito ergo sum * errare humanum est * quote erat demonstrandum *
    Wenn ich denke, ist das ein Fehler und das beweise ich täglich
    Blog Xing
    Mittwoch, 25. Mai 2011 10:32
  • Oh. Sorry. Ich habe nicht zu Ende geschrieben. Diese "ddd" ändert sich von Zeile zu Zeile. Mal ddd1, ddd2, ddd usw.
    Mittwoch, 25. Mai 2011 10:53
  • Und nach welcher genauen Logik ändert sich der Wert? Du wirst ja vermutlich für den Cursor auch nicht mehrere hunderte Fallunterscheidungen haben, wann welcher Wert verwendet wird?
    Olaf Helper
    * cogito ergo sum * errare humanum est * quote erat demonstrandum *
    Wenn ich denke, ist das ein Fehler und das beweise ich täglich
    Blog Xing
    Mittwoch, 25. Mai 2011 11:02
  • Ich habe eine Variable @takt=5 min

    In die Spalte row2 soll folgendes stehen:

     

    17:00

    17:05

    17:10

    usw.

    Mittwoch, 25. Mai 2011 11:11
  • Geht es eventuell etwas genauer, bitte? Welchen Datentyp hat Row2 und was steht aktuell in Row2 drin? Sind es evtl Uhrzeiten die auf einen 5 min Wert "gerundet" werden sollen?
    Olaf Helper
    * cogito ergo sum * errare humanum est * quote erat demonstrandum *
    Wenn ich denke, ist das ein Fehler und das beweise ich täglich
    Blog Xing
    Mittwoch, 25. Mai 2011 11:20
  • andrej75 wrote:

    DECLARE cur CURSOR FOR
    SELECT row1, row2 FROM tab1;
    OPEN cur;
    FETCH NEXT FROM cur
    INTO @row1, @row2;
    WHILE @@FETCH_STATUS = 0 BEGIN

     UPDATE tab1 SET @row2 = @row1 + 'ddd'
       WHERE CURRENT OF cur

    END

    Ich möchte in row2 Inhat auslesen und mit z.B. String "ddd" verketten und
    in row2 zurück schreiben.

    HTH
    Henry

    • Als Antwort markiert andrej75 Mittwoch, 25. Mai 2011 12:28
    Mittwoch, 25. Mai 2011 11:21
  • row2 ist smalldatetime. in erste Zeile steht Zeit und Datum von jeztige Zeitpunkt. In jeder Zeile muss Zeit auf 5 Min gegenüber vorherige Zeile erhöht werden.

    Mittwoch, 25. Mai 2011 11:36
  • Und wie ist "vorherige Zeile" definiert? In einer Datenbank sind Daten eine Menge, da gibt es per se erstmal kein vorherige oder nachfolgende Zeile; das definiert sich höchsten nachfolgend über die gewählte Sortierung.

    Bitte poste doch mal das (gekürzte) Create Script für die Tabelle (inkl. PK Def) + ein paar Beispieldaten als INSERT Statements und wie das gewünschte Ergebnis für die Beispieldaten aussehen soll.


    Olaf Helper
    * cogito ergo sum * errare humanum est * quote erat demonstrandum *
    Wenn ich denke, ist das ein Fehler und das beweise ich täglich
    Blog Xing
    Mittwoch, 25. Mai 2011 11:43
  • Hier ist die ausgang Zustand:

    tab1

    row1      row2

    value1    NULL

    value2    NULL

    value2    NULL

    ......

     

    Ich ich schreibe zuerst in Zeile 1 jetztitige Zeitpunkt (in Cursor habe ich gedacht)

    tab1

    row1 row2

    value1    01.01.2011 12:00:00

    value2 NULL

    value2 NULL

    ......

     

    danach

    tab1

    row1 row2

    value1    01.01.2011 12:00:00

    value2    01.01.2011 12:05:00

    value2 NULL

    ......

     

    usw.

    Mittwoch, 25. Mai 2011 11:47
  • Dich um etwas zu bitten, gestaltet sich wirklich schwierig ....

    Also, mittels der ROW_NUMBER() Funktion kann man je Datensatz eine laufende Nummer erzeugen, also 1 - n; über die ORDER BY Klausel kannst Du festlegen, wie die Reihenfolge ist (um so vorherige / nachfolgend festzulegen), hier eben row1.

    Dann definierst Du eine @start Wert und addierst dann mit DATEADD immer 5 min * die laufende Nummer auf; sieht da so aus:

    CREATE TABLE #tbl

        (row1 int, row2 smalldatetime);

     

    INSERT INTO #tbl (row1) VALUES (1);

    INSERT INTO #tbl (row1) VALUES (2);

    INSERT INTO #tbl (row1) VALUES (3);

    INSERT INTO #tbl (row1) VALUES (4);

    INSERT INTO #tbl (row1) VALUES (5);

    GO

     

    DECLARE @start smalldatetime;

    SET @start = {ts N'2011-01-01 12:00:00.000'}

     

    ;WITH cte AS

       (SELECT *, row_number() over (order by row1) - 1 AS LfdNr

        FROM #tbl)

    UPDATE cte

    SET row2 = DATEADD(mi, LfdNr * 5, @start)

     

    SELECT *

    FROM #tbl;

     

    GO

    DROP TABLE #tbl;

     


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



    • Als Antwort markiert andrej75 Mittwoch, 25. Mai 2011 12:28
    Mittwoch, 25. Mai 2011 12:05
  • Danke für Eure Hilfe.

     

    Die letzte Frage habe ich noch, welche die beide Lösungen braucht wengiger Serverresources. cte oder cursor.

    Mittwoch, 25. Mai 2011 13:07
  • Falls Du bereits einen Cursor offen hast, sollte der Update mit CURRENT OF fast kostenfrei sein weil der Datensatz nicht mehr neu gesucht werden muss. Der Lock sollte auch schon da sein.

    Ein "normaler" Update dürfte intern genauso einen Cursor anlegen, wie Du das machst, aber nach dem Update die Ressourcen gleich wieder freigeben.

    Wenn Du's für den konkreten Fall genauer wissen willst, analysiere es im SSMS mit hilfe des Planes und der Kosten.

    Gruss

    Henry

    Mittwoch, 25. Mai 2011 14:57
  • Eine Mengenoperation ist immer effizienter und performanter als eine Cursoroperation; einen Cursor sollte man immer nur dann verwenden, wenn man wirklich keine andere Möglichkeit findet.
    Olaf Helper
    * cogito ergo sum * errare humanum est * quote erat demonstrandum *
    Wenn ich denke, ist das ein Fehler und das beweise ich täglich
    Blog Xing
    Mittwoch, 25. Mai 2011 16:08