Ist es möglich, mehrere Aktualisierungen mit einer einzelnen UPDATE SQL-Anweisung durchzuführen?

Nehmen wir an, ich habe eine Tabelle tbl mit den Spalten id und Titel . Ich muss alle Werte der Titelspalte ändern:

  1. von 'a-1' zu 'a1', "-30-' von 'a.1' zu 'a1', "-31-' von 'b-1' zu 'b1', "-32-' von 'b.1' nach 'b1'.

Im Moment führe ich zwei UPDATE-Anweisungen aus:

UPDATE tbl SET title='a1' WHERE title IN ('a-1', 'a.1')
UPDATE tbl SET title='b1' WHERE title IN ('b-1', 'b.1')

Dies ist überhaupt kein Problem, wenn die Tabelle klein ist und die einzelne Anweisung in weniger als einer Sekunde abgeschlossen wird und Sie nur wenige Anweisungen zum Ausführen benötigen.

Sie haben es wahrscheinlich zu Gast - ich habe eine riesige Tabelle zu behandeln (eine Aussage in etwa 90 Sekunden abgeschlossen), und ich habe eine große Anzahl von Updates durchzuführen.

Ist es also möglich, die Aktualisierungen zusammenzuführen, sodass die Tabelle nur einmal abscanniert wird? Oder vielleicht gibt es einen besseren Weg, um in einer Situation wie dieser umzugehen.

EDIT: Beachten Sie, dass die realen Daten, mit denen ich arbeite, und die Änderungen an den Daten, die ich ausführen muss, nicht wirklich so einfach sind - die Zeichenfolgen sind länger und sie folgen keinem Muster (es sind Benutzerdaten, also können keine Annahmen gemacht werden - es kann alles sein).

Antwort auf "Ist es möglich, mehrere Aktualisierungen mit einer einzelnen UPDATE SQL-Anweisung durchzuführen? " 5 von antworten

Wenn die Transformationen so einfach sind wie Ihre Beispiele, können Sie das Update mit ein wenig String-Manipulation machen:

UPDATE tbl 
SET title = left(title, 1) + right(title, 1) 
WHERE title IN ('a-1', 'a.1', 'b-1', 'b.1')

Würde so etwas für Sie funktionieren?

Sie können eine Anweisung und eine Reihe von Fallanweisungen

update tbl
  set title = 
    case
      when title in ('a-1', 'a.1') then 'a1'
      when title in ('b-1', 'b.1') then 'b1'
      else title
    end

Natürlich wird dies zu einem Schreiben auf jeden Datensatz führen, und mit Indizes kann es ein Problem sein, so dass Sie nur die Zeilen herausfiltern können, die Sie ändern möchten:

update tbl
  set title = 
    case
      when title in ('a-1', 'a.1') then 'a1'
      when title in ('b-1', 'b.1') then 'b1'
      else title
    end
where
  title in ('a.1', 'b.1', 'a-1', 'b-1')

Das reduziert die Anzahl der Schreibvorgänge in die Tabelle.

oder

   Update Table set 
     title = Replace(Replace(title, '.', ''), '-', '')
   Where title Like '[ab][.-]1'

In einem allgemeineren Fall, in dem es viele hunderte von Zuordnungen zu jedem der neuen Werte geben könnte, erstellen Sie eine separate Tabelle der alten und neuen Werte und verwenden diese dann in der UPDATE-Anweisung. In einem Dialekt von SQL:

CREATE TEMP TABLE mapper (old_val CHAR(5) NOT NULL, new_val CHAR(5) NOT NULL);
...multiple inserts into mapper...
INSERT INTO mapper(old_val, new_val) VALUES('a.1', 'a1');
INSERT INTO mapper(old_val, new_val) VALUES('a-1', 'a1');
INSERT INTO mapper(old_val, new_val) VALUES('b.1', 'b1');
INSERT INTO mapper(old_val, new_val) VALUES('b-1', 'b1');
...etcetera...

UPDATE tbl
   SET title = (SELECT new_val FROM mapper WHERE old_val = tbl.title)
   WHERE title IN (SELECT old_val FROM mapper);

sind beide Auswahlanweisungen entscheidend. Die erste ist eine korrelierte Unterabfrage (nicht unbedingt schnell, aber schneller als die meisten Alternativen, wenn die Mapper-Tabelle Tausende von Zeilen hat), die den neuen Wert aus der Zuordnungstabelle abruft, die dem alten Wert entspricht. Die zweite stellt sicher, dass nur die Zeilen geändert werden, die einen Wert in der Zuordnungstabelle haben. Dies ist von entscheidender Bedeutung, da andernfalls der Titel für diese Zeilen ohne Zuordnungseintrag auf null gesetzt wird (und das waren die Datensätze, die ok waren, bevor Sie angefangen haben).

Für einige Alternativen sind die CASE-Operationen in Ordnung. Wenn Sie jedoch Hunderte oder Tausende oder Millionen von Zuordnungen ausführen müssen, werden Sie wahrscheinlich die Grenzen der SQL-Anweisungslänge in Ihrem DBMS überschreiten.

Arbeiten von Jonathans Antwort.

UPDATE tbl
   SET title = new_val
FROM mapper
WHERE title IN (SELECT old_val FROM mapper)
     AND mapper.old_val = tbl.title;

Seine ursprüngliche Version würde eine große Anzahl von Lesevorgängen für die Mapper-Tabelle erfordern.