Zeilenweises Durchlaufen einer SELECT-Anweisung

mindhunter

Benutzer
Beiträge
22
Hallo,

in einer Microsoft SQL Datenbank gibt es eine Tabelle, welche mit Parametern geändert werden soll. Als Beispiel habe ich ein Script, das diese Tabelle anlegt. Mit einer SELECT-Anweisung hole ich bestimmte Daten. Nun möchte ich diesen SELECT Zeile für Zeile durchlaufen und Werte neu setzten und mir die geänderten Daten in einem SELECT wieder anzeigen lassen, bzw. ausgeben. Z.B. wenn site_id = 3 dann schreibe in Test ‘blabla‘, site_id = 5 dann ‘bliblablup‘ in Test. Die Anzahl der Zeilen erfasse ich mit SELECT COUNT(*) FROM DUAL oder ist die FETCH-Anweisung dafür besser geeignet?

Vielen Dank für eure Hilfe
Stefan



---
Code:
DROP TABLE DUAL
 
CREATE TABLE DUAL
(
    site_id [int] NULL,
    Name [nchar](50) NULL,
    Abk [nchar](10) NULL,
    Cur [nchar](10) NULL,
    Class [nchar](10) NULL,
    Product [nchar](10) NULL,
    Project [nchar](10) NULL,
    Color_ID [nchar](10) NULL,
    Test [nchar](10) NULL
)
 
 
INSERT INTO DUAL (site_id, Name, Abk, Cur, Class, Product, Project, Color_ID, Test)
VALUES (0,'0','NULL','EUR','NULL','NULL','NULL','NULL','NULL')
 
INSERT INTO DUAL (site_id, Name, Abk, Cur, Class, Product, Project, Color_ID, Test)
VALUES (1,'BU SC','BU SC','EUR','BU','NULL','NULL','0','NULL')
 
INSERT INTO DUAL (site_id, Name, Abk, Cur, Class, Product, Project, Color_ID, Test)
VALUES (2,'CI','NULL','EUR','BS','NULL','NULL','6','NULL')
 
INSERT INTO DUAL (site_id, Name, Abk, Cur, Class, Product, Project, Color_ID, Test)
VALUES (3,'PA','NULL','EUR','BS','NULL','NULL','78','NULL')
 
INSERT INTO DUAL (site_id, Name, Abk, Cur, Class, Product, Project, Color_ID, Test)
VALUES (4,'PI','NULL','EUR','BS','NULL','NULL','30','NULL')
 
INSERT INTO DUAL (site_id, Name, Abk, Cur, Class, Product, Project, Color_ID, Test)
VALUES (5,'PP','NULL','EUR','BS','NULL','NULL','42','NULL')
 
INSERT INTO DUAL (site_id, Name, Abk, Cur, Class, Product, Project, Color_ID, Test)
VALUES (6,'CI (HQ)','NULL','EUR','Site','NULL','NULL','7','NULL')
 
INSERT INTO DUAL (site_id, Name, Abk, Cur, Class, Product, Project, Color_ID, Test)
VALUES (7,'MF-K (PI)','NULL','EUR','Site','NULL','NULL','31','NULL')
 
INSERT INTO DUAL (site_id, Name, Abk, Cur, Class, Product, Project, Color_ID, Test)
VALUES (8,'Concord','NULL','EUR','Site','NULL','NULL','5','NULL')
 
INSERT INTO DUAL (site_id, Name, Abk, Cur, Class, Product, Project, Color_ID, Test)
VALUES (10,'Houston','NULL','EUR','Site','NULL','NULL','79','NULL')
 
INSERT INTO DUAL (site_id, Name, Abk, Cur, Class, Product, Project, Color_ID, Test)
VALUES (11,'Singapore','NULL','EUR','Site','NULL','NULL','77','NULL')
 
SELECT site_id, Name, Abk, Cur, Class, Product, Project, Color_ID, Test  FROM DUAL WHERE Class = 'BS'
 
 
 
DECLARE @numRow int
DECLARE row_cursor CURSOR FOR
SELECT site_id, Color_ID, Test FROM DUAL WHERE Class ='BS';
 
SET @numRow =  (SELECT COUNT(*) FROM DUAL)
 
OPEN row_cursor;
FETCH NEXT FROM row_cursor;
 
WHILE @@FETCH_STATUS = 0
    BEGIN
 
    -- site_id = 3 dann schreibe in Test  ‘bla_bla‘, site_id = 5 dann ‘bli_bla_blup‘ in Test.
    -- SELECT site_id, Color_ID, Test FROM DUAL...
 
    FETCH NEXT FROM row_cursor
    END
 
CLOSE row_cursor;
DEALLOCATE row_cursor;
 
Werbung:
Hallo,

in einer Microsoft SQL Datenbank gibt es eine Tabelle, welche mit Parametern geändert werden soll. Als Beispiel habe ich ein Script, das diese Tabelle anlegt. Mit einer SELECT-Anweisung hole ich bestimmte Daten. Nun möchte ich diesen SELECT Zeile für Zeile durchlaufen und Werte neu setzten und mir die geänderten Daten in einem SELECT wieder anzeigen lassen, bzw. ausgeben. Z.B. wenn site_id = 3 dann schreibe in Test ‘blabla‘, site_id = 5 dann ‘bliblablup‘ in Test. Die Anzahl der Zeilen erfasse ich mit SELECT COUNT(*) FROM DUAL oder ist die FETCH-Anweisung dafür besser geeignet?

SQL in Schleifen ist fast immer ganz schlecht. Wo kommen denn die Daten her? Aus einer anderen Tabelle?

Angenommen, Du hast 2 Tabellen, mindhunter1 und 2, erstere soll geändert werden mit den Daten aus 2. Dazu dienst übrigens UPDATE. Also, Du hast:

Code:
test=# create table mindhunter1(id int, val int);
CREATE TABLE   
Time: 267,314 ms   
test=*# insert into mindhunter1 select s, null from generate_series(1,10) s;
INSERT 0 10   
Time: 0,933 ms   
test=*# select * from mindhunter1 ;   
 id | val   
----+-----   
  1 |   
  2 |   
  3 |
  4 |
  5 |
  6 |
  7 |
  8 |
  9 |
 10 |
(10 rows)

Time: 0,262 ms
test=*# create table mindhunter2(id int, val int);
CREATE TABLE
Time: 20,248 ms
test=*# insert into mindhunter2 values (3,5);
INSERT 0 1
Time: 0,322 ms
test=*# insert into mindhunter2 values (8,15);
INSERT 0 1
Time: 0,127 ms

Soweit klar, oder?

Code:
test=*# update mindhunter1 set val=mindhunter2.val from mindhunter2 where mindhunter1.id=mindhunter2.id;
UPDATE 2
Time: 0,485 ms
test=*# select * from mindhunter1;
 id | val
----+-----
  1 |
  2 |
  4 |
  5 |
  6 |
  7 |
  9 |
 10 |
  3 |  5
  8 |  15
(10 rows)

Time: 0,147 ms

Ist jetzt PostgreSQL, geht aber mit M$SQL ganz sicher auch so.
 
Die Daten kommen aus einer anderen Tabelle oder aus Eingabefeldern aus einer Web-Anwendung. Ich jetzt noch nicht klar. Ich wollte sehen und versethen, wie eine Schleife funktioniert.
 
Die Daten kommen aus einer anderen Tabelle oder aus Eingabefeldern aus einer Web-Anwendung. Ich jetzt noch nicht klar. Ich wollte sehen und versethen, wie eine Schleife funktioniert.

Wie gesagt: Schleifen auf Mengen von Daten, also in Datenbanken, sind fast immer ganz übel. Das geht mit wenigen Datensätzen, wenn Du richtige Tabellen mit Millionen Rows hast fliegt es Dir um die Ohren.
 
Es gibt mehrere Wege, der Verzicht auf Schleifen ist sicher immer zu empfehlen. In deinem Fall könnte ein JOIN im UPDATE Befehl hilfreich sein (siehe akretschmers Join) und dir die Daten passend liefern. Auch eine CASE Anweisung kann innerhalb von UPDATE nützlich sein.

Du kannst auch ganz ohne CURSOR abreiten, z.B. mit einer WHILE Schleife. Bietet aber glaube ich keinen Geschwindigkeitsvorteil.
 
Werbung:
Code:
DECLARE @counter INT,
        @pk UNIQUEIDENTIFIER

SET        @counter = (    SELECT    count(1)
                        FROM    tabelle )

WHILE    @counter > 0
BEGIN
    SET        @pk = (    SELECT    pk
                    FROM (    SELECT    TOP (@counter) pk,
                                    ROW_NUMBER() OVER (ORDER BY pk) AS zeilennr
                            FROM    tabelle
                            ORDER BY pk ) x
                    WHERE    x.zeilennr = @counter )

    -- Aktion

    SET        @counter = @counter - 1
END
 
Zurück
Oben