Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi UPDATE nicht ausführen, wenn nichts? (https://www.delphipraxis.net/189487-update-nicht-ausfuehren-wenn-nichts.html)

himitsu 17. Jun 2016 11:00

Datenbank: postgres • Version: 5.3 • Zugriff über: PgDAC

UPDATE nicht ausführen, wenn nichts?
 
Warum hat das UPDATE-SQL kein Flag für "tu nichts, wenn sich kein Feld ändert" ?

Wenn ich nicht will, dass Trigger ausgelöst werden, wenn sich nicht ändert, dann darf ich alle Felder im SET nochmal im WHERE gegenprüfen.
> Doppelter Code
> OK, wenn es richtig viel wird, könnte man die Auswertungen z.B. in einen LATERAL-JOIN auslagern und im WHERE/SET nur noch das Ergebnis vergleichen/zuweisen.

SQL-Code:
UPDATE test
SET aaa = hierganzviel
    bbb = hierauchganzviel
WHERE id = ...
  AND aaa IS DISTINCT FROM hiernochmalganzviel
  AND bbb IS DISTINCT FROM hierauchnochmalganzviel
Aber so ein "kurzer" Befehl ala "DISTINCT" wäre doch eigentlich ganz praktisch?

p80286 17. Jun 2016 11:35

AW: UPDATE nicht ausführen, wenn nichts?
 
Zitat:

Zitat von himitsu (Beitrag 1340408)
Warum hat das UPDATE-SQL kein Flag für "tu nichts, wenn sich kein Feld ändert" ?

Weil der mündige Benutzer nie im Leben bereits vorhandene Daten mit sich selbst überschreiben würde?
Und wenn doch, dann hat er gute Gründe dafür?
:stupid:

Gruß
K-H

bra 17. Jun 2016 12:35

AW: UPDATE nicht ausführen, wenn nichts?
 
Außerdem ist der DB-Aufwand, das zu prüfen auch einfach höher als einfach ohne Prüfung zu schreiben. Man müsste ja bei jedem Schreibvorgang vorher erst noch prüfen, ob die Daten übereinstimmen.

himitsu 17. Jun 2016 14:26

AW: UPDATE nicht ausführen, wenn nichts?
 
Darum ja auch als "aktivierbares" Zusatzfeature, das Standardmäßig nicht aktiv ist. :zwinker:
Um nur die Trigger neu anzustoßen, machen Viele oft einfach einen Post ohne Änderung, ala
Delphi-Quellcode:
SET aaa=aaa
Der Aufwand das selber zu prüfen ist auch größer (längeres SQL und eventuell doppelte Auswertung), als wenn die DB das von selber schon könnte.


Ich finde das wäre ein gutes Grundfeature, so wie ein INSERT OR UPDATE.

Fritzew 17. Jun 2016 14:34

AW: UPDATE nicht ausführen, wenn nichts?
 
Oder im Trigger prüfen was und ob sich etwas geändert hat und nur dann eine Aktion ausführen

TBx 17. Jun 2016 15:38

AW: UPDATE nicht ausführen, wenn nichts?
 
Zitat:

Zitat von Fritzew (Beitrag 1340435)
Oder im Trigger prüfen was und ob sich etwas geändert hat und nur dann eine Aktion ausführen

genau, das ist das Standardprocedere!

Sir Rufo 17. Jun 2016 18:34

AW: UPDATE nicht ausführen, wenn nichts?
 
Nur mal so dahingedacht:
  • Der
    SQL-Code:
    UPDATE
    -Trigger wird immer ausgelöst, wenn ein
    SQL-Code:
    UPDATE
    Statement abgesetzt wird.
  • Ein
    SQL-Code:
    TIMESTAMP
    Feld (mit
    SQL-Code:
    ON UPDATE CURRENT_TIMESTAMP
    ) wird nur dann aktualisiert, wenn sich wirklich Daten in der Zeile ändern.
Im
SQL-Code:
UPDATE
-Trigger braucht man jetzt also nur noch zu prüfen, ob es eine Änderung im
SQL-Code:
TIMESTAMP
Feld gibt (
SQL-Code:
IF OLD.ts <> NEW.ts THEN
) und schon kann man darauf gesondert reagieren.

So funktioniert es z.B. bei MySQL

jobo 18. Jun 2016 22:51

AW: UPDATE nicht ausführen, wenn nichts?
 
Per Trigger mit :new/ :old zu arbeiten ist wahrscheinlich das gängige Verfahren.
Alternativ kannst Du das Update so gestalten, dass es
- 0 Rows betrifft und damit auch
- ein Trigger nicht zündet bzw.
- ein Trigger gar nicht definiert sein muss oder
- unspezifisch sein kann:
Für ein "leeres" Update kann man z.B. als Bedingung
Code:
where exists
mit
Code:
Select <aktueller Feldinhalt/Felder> from UpdateTable where..
except
Select <neue Feldwerte oder bestehende Feldwerte> from <jenachdem> <where ..>
kombinieren.

Das ist wahrscheinlich nicht viel weniger als "ganz viel und hier auch ganz viel", aber es hat den Charme, dass man nicht nachdenken muss und die Statements anhand der Felder der Tabelle generisch bauen kann (ohne PK und andere frei wählbare Ausnahmen). Ob es dann zündet, regelt das "except".
Was final geupdated wird, steht unabhängig davon in der Update ExpressionList. Kann man gut finden, weil weiterer Freiheitsgrad, kann aber auch falsch gemacht werden.

Andere DB können im Update statt der ExpressionList auch gleich Selects verwenden, dass macht es etwas eleganter.

Unterscheiden muss man hier bei den Where Bedingungen natürlich zwischen SingleRow Updates und Massenupdates.

Sir Rufo 19. Jun 2016 17:09

AW: UPDATE nicht ausführen, wenn nichts?
 
Aber warum so umständlich, wenn man das mit einem TIMESTAMP Feld komplett erschlagen kann?

jobo 20. Jun 2016 08:13

AW: UPDATE nicht ausführen, wenn nichts?
 
Es ist einfach eine Möglichkeit, damit und mit anderen Problemen umzugehen. Sozusagen eine Ikea Antwort, entdecke die Möglichkeiten.

Ich brauche/will/darf keinen Trigger,
Ich brauche/will/darf kein Update Feld,
Ich habe in PG nicht direkt die MySQL On Update Definition zur Verfügung,

Es ist flexibler als ein Catchall Update Timestamp:
Wenn bspw. beim Kunden ein Tippfehler in der Anschrift korrigiert wird, interessiert mich vielleicht dieses Update Event, wechselt aber ein Flag / Statusfeld durch eine BusinessOperation seinen Wert, interessiert mich das vielleicht überhaupt nicht als Kundenupdate Event, weil die BO den Event implizit logged/dokumentiert.

Und kompliziert ist ja relativ, innerhalb eines Update Statementgerüsts ist es nichts viel mehr als die Wiederholung einer Feldliste/Parameterliste.
Update myTable
set
<feldliste>
<parameterliste>
where
<corecondition>
and exists
(
select <feldliste> from myTable where <corecondition>
except
select <parameterlist> [from myTable where <corecondition]>
)

himitsu 20. Jun 2016 10:36

AW: UPDATE nicht ausführen, wenn nichts?
 
Zitat:

Zitat von jobo (Beitrag 1340601)
Und kompliziert ist ja relativ, innerhalb eines Update Statementgerüsts ist es nichts viel mehr als die Wiederholung einer Feldliste/Parameterliste.

Jupp, dieses Doppelte hätte man sich ja sparen können, wenn das UPDATE-Statement dafür eine integrierte Funktion hätte.

So ala dem
Delphi-Quellcode:
SELECT DISTINCT ...
(EIN Befehl zum Filtern von Wiederholungen) vielleicht ein
Delphi-Quellcode:
UPDATE CHANGED table SET ...
.


Im Prinzip kann ich ja "einfach" Den TEIL aus dem SET ins WHERE kopieren,
drumrum ein
Delphi-Quellcode:
AND ( ...)
, aus den Kommas je ein OR und fertig.

Vor eine Weile hatte ich ein Statement, da war das im SET nur knapp 20 Zeilen lang und bissl breit ... da sieht das "einfach" bissl blöd aus und bei Änderungen muß man dann auch beide Stellen anpassen, sonst knallt es ja.

p80286 20. Jun 2016 11:18

AW: UPDATE nicht ausführen, wenn nichts?
 
Jetzt stell Dir vor, die Durchführung des Updates ist von einem Feld abhängig, das nicht "upgedated" wird, da kommst Du mit einem "wenn alles gleich ist" nicht so weit. Übrigens unterdrückt DISTINCT nur die Ausgabe gleicher Zeilen, das ist nur Kosmetik. Wenn es doppelte Datensätze geben sollte, sollte man auch wissen warum.

Gruß
K-H

Sir Rufo 20. Jun 2016 11:20

AW: UPDATE nicht ausführen, wenn nichts?
 
Hmmm,
SQL-Code:
UPDATE
hat so etwas schon eingebaut.

Für den Trigger verwendet man ein TIMESTAMP Feld und in der Anwendung fragt man nach der Ausführung
Delphi-Quellcode:
RecordsAffected
ab (was dann 0 ist, wenn die Werte gleich waren).

Man kann sich das auch selber zusammenbauen wenn einem das nicht reicht

himitsu 20. Jun 2016 11:42

AW: UPDATE nicht ausführen, wenn nichts?
 
Zitat:

RecordsAffected
Das UPDATE steht in einem Trigger einer anderen Tabelle, da gibt es das TDataSet nicht.
Es gibt zwar das FOUND (Update hat mindestens einen Datensatz getroffen ... abhängig vom WHERE), aber das ist ja keine Lösung, da es ja nicht meinen Trigger und den nachfolgenden Code, sondern andere Trigger betrifft (und die sind oft paar Jahrzehnte alt und demnach nicht immer gut gebaut).

Da man auch nicht "weiß" was für Trigger überall dran hängen oder mal dran hängen werden, ist auch ein DISABLE TRIGGER eine Lösung.



SELECT DISTINCT braucht ja auch keiner, da man das über ein passendes GROUP BY oder WHERE auch selber bauen könnte.

SQL-Code:
UPDATE CHANGED test
SET aaa = hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel
      hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel
      hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel
      hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel,
    bbb = hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
WHERE id = ...
  AND nochwas
sähe doch besser aus, als
SQL-Code:
UPDATE test
SET aaa = hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel
      hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel
      hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel
      hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel,
    bbb = hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
WHERE id = ...
  AND nochwas
  AND (aaa = hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel
      hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel
      hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel
      hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel_hierganzviel
    OR bbb = hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel
      hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel_hierauchganzviel)
wenn das DBMS aaa mit dem Ergebnis von hierganzviel vergleichen und nur bei Unterschied das Update machen würde.

Ja OK, man könnte auch ein gang blöd eine Prüfung ala
SQL-Code:
IF old = new THEN
  RETURN new
END IF;
in alle Trigger rein machen, aber wozu überhaupt den Datensatz updaten, wenn sich doch nix ändert.
PS: Wir haben an fast allen Tabellen einen echt doofen automatisch generierten Trigger, der nichts prüft und bei jedem UPDATE ein Feld modified_date=current_time setzt.
und dann teilweise noch paar Trigger, die manchmal nicht grade wenig machen. (z.B. die Mengen/Preise von allem neu berechnen)

Das GANZ_VIELE könnte ich zwar in einen LATERAL JOIN auslagern und dann im WHERE und SET quasi kurze temporäre Variablenbenutzen, aber da muß ich auch erstma gucken, wie das nochmal ging.

Bin doch bestimmt nicht der Einzige, der das bissl "doof" findet, da hätte man da doch auch gleich was in der SQL-Syntax für vorsehen können? :angle:

Sir Rufo 20. Jun 2016 11:50

AW: UPDATE nicht ausführen, wenn nichts?
 
Darum sagte ich ja auch in der Anwendung kann man RecordsAffected abfragen - im Trigger verwendet man den TimeStamp

Sir Rufo 20. Jun 2016 11:55

AW: UPDATE nicht ausführen, wenn nichts?
 
Wenn das mit dem TimeStamp/RecordsAffected nicht ausreicht wird man auf so ein Konstrukt zurückgreifen müssen.

Da dieses Konstrukt aber gewissen Regeln folgt, kann man sich auch ein kleines Programm schreiben, was einem die Erstellung dieser Statements erleichtert :stupid:

jobo 20. Jun 2016 12:55

AW: UPDATE nicht ausführen, wenn nichts?
 
Zitat:

Zitat von himitsu (Beitrag 1340614)
So ala dem
Delphi-Quellcode:
SELECT DISTINCT ...
(EIN Befehl zum Filtern von Wiederholungen) vielleicht ein
Delphi-Quellcode:
UPDATE CHANGED table SET ...
.

Im Prinzip kann ich ja "einfach" Den TEIL aus dem SET ins WHERE kopieren,
drumrum ein
Delphi-Quellcode:
AND ( ...)
, aus den Kommas je ein OR und fertig.

Der Teil in meinem Vorschlag, der mit dem "Except" arbeitet, dient genau dazu, den Vergleich "Bestandsdaten zu Änderungen" zu übernehmen und bei Gleichheit eine leere Menge auszuspucken, sodass Update ins Leere läuft (siehe Thema des Threads), also 0 Rows affected.
Mit And/Or Muss man da innerhalb der Felder nichts machen, AND/OR benötigt man nur, um die Basisbedingung* des Update mit dem Except Teil zu verbinden.
Die Syntax bei PG erlaubt nun das Update genauso aufzubauen, wie eine Select Clause, einfach eine Feld- bzw Werteliste eintragen.
Damit ist "notfalls" dann das Generieren, eines solchen Statements sehr simpel.

@SirRufo: Was meinst Du in #13 mit "soetwas". Ich kenne nur updates, deren Updatecount (Rows Affected) über die Where Bedinung definiert sind.

@p80286: Die Anhängigkeit des Updates von anderen Feldern war nicht gefragt, sondern "hat sich überhaupt was geändert" oder? Aber so oder so, wenn das Update allein den Umfang der Updates bestimmt (ohne Trigger), hat man die größte Flexibilität.

*Die Basisbedinung kann natürlich auch n Haufen And/Or enthalten, aber das war nicht gemeint oder?

Sir Rufo 20. Jun 2016 13:41

AW: UPDATE nicht ausführen, wenn nichts?
 
@jobo
Das meine ich damit
Delphi-Quellcode:
Query.SQL.Text := 'INSERT INTO foo ( id, bar ) VALUES ( 1, "foo" )';
Query.ExecSQL(); // Betroffene Zeilen 1

Query.SQL.Text := 'UPDATE foo SET bar = "foobar" WHERE id = 1';
Query.ExecSQL(); // Betroffene Zeilen 1

Query.SQL.Text := 'UPDATE foo SET bar = "foobar" WHERE id = 1';
Query.ExecSQL(); // Betroffene Zeilen 0 !!!!!

jobo 20. Jun 2016 19:12

AW: UPDATE nicht ausführen, wenn nichts?
 
Zitat:

Zitat von Sir Rufo (Beitrag 1340642)
Das meine ich damit
Delphi-Quellcode:
..snipp
Query.SQL.Text := 'UPDATE foo SET bar = "foobar" WHERE id = 1';
Query.ExecSQL(); // Betroffene Zeilen 0 !!!!!

In meiner Welt kommt auch hier "Betroffene Zeilen 1" raus. Mir ist nicht bewusst, dass irgendwelche DB sich so verhalten.

Sir Rufo 20. Jun 2016 20:30

AW: UPDATE nicht ausführen, wenn nichts?
 
Zitat:

Zitat von jobo (Beitrag 1340664)
In meiner Welt kommt auch hier "Betroffene Zeilen 1" raus. Mir ist nicht bewusst, dass irgendwelche DB sich so verhalten.

Wenn du MySQL als DB betrachtest, dann hast du damit schon eine

jobo 21. Jun 2016 06:16

AW: UPDATE nicht ausführen, wenn nichts?
 
Zitat:

Zitat von Sir Rufo (Beitrag 1340665)
Zitat:

Zitat von jobo (Beitrag 1340664)
In meiner Welt kommt auch hier "Betroffene Zeilen 1" raus. Mir ist nicht bewusst, dass irgendwelche DB sich so verhalten.

Wenn du MySQL als DB betrachtest, dann hast du damit schon eine

Interessant! Klar betrachte ich die als DB. Ich arbeite aber selbst nicht produktiv damit. IdR sind es nur Performance- oder Vorgehensfragen, wo ich auch mal mit mySQL zu tun hab, also stumpf SQL.
Jetzt muss ich mir noch überlegen, wie ich das finden soll.
Danke, Sir Rufo!

Kennt jemand noch mehr davon?


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:07 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz