(Oracle) Subselect für Update soll pk zurück liefern und bringt mich um den Verstand

Atlantiz

Grünschnabel
Hallo Forum

Beim Suchen nach einer Lösung bin ich auf dieses Forum gestossen.
Habe eigentlich ein lächerliches Thema, das mich aber schon viel Zeit gekostet hat.

Folgende Tabelle:
T_TRAD_UPE_SB mit folgenden Spalten:
  • UPE_PK (PK zum Unverbindlichen VK Preis)
  • Z_TLN (Teilenummern)
  • GUELTIG_AB (Preisgültigkeit)
  • UPE_QUELLE (Datenquelle aus welcher der Preis stammt 1 oder 2)
  • UPE (Unverbindlicher VK Preis)
  • MAX (Kenzzeichnungsflag der Datensätze, die innerhalb der Gruppe
    ZTL; GUELTIG_AB & UPE_QUELLE den Max Preis haben
ZIEL:
Per Update soll das Feld max = 1 gesetzt werden, bei den Datensätzen (es können mehrere DS sein), die in der Gruppe(GROUP BY Z_TLN, UPE_QUELLE, GUELTIG_AB) den maximalen UPE haben.

Ich schaffe es nicht (roter Bereich), den Subselect so zu formulieren, dass ich die ID´s der betroffenen Datensätze (UPE_PK) mit dem höchsten UPE der Gruppe bekomme.

also so ungefähr:
SQL:
update T_TRAD_UPE_SB dst
SET
dst.MAX = 1
WHERE
dst."UPE_PK" = src."UPE_PK"
AND
dst."UPE" IN (SELECT Max(src.UPE) 
FROM T_TRAD_UPE_SB src
GROUP BY
src."Z_TLN", src."UPE_QUELLE", src."GUELTIG_AB") ;

Ein Subselect
SELECT Max(src.VAL) FROM ATLANTIS src GROUP BY src."G1", src."G2", src."G3" funktioniert.
Wie bekomme ich jetzt dazu von genau diesen Datensätzen mit MAX Werten in der Gruppe die jeweiligen PK`s zurück?

Vielleicht läßt es sich auch mit Analysefunktionen erschlagen, da bin ich aber noch total feucht hinter den Ohren.

Vielen Dank für einen kurzen Tip... oder gerne auch 2-3 gute Suchbegriffe für Google.
Ich finde aktuell immer nur Lösungen über die max(ID) also neuesten Datensatz oder Lösungenansätze,
wenn es nur einen Datensatz mit MAX Wert gibt usw... was aber nicht weiter hilft.

Habe schon in einem anderen Forum angefragt, jedoch nur Lösungen erhalten, die auf Oracle leider nicht laufen...

Euch bereits jetzt vielen Dank!

Atlantis
 
Zuletzt bearbeitet von einem Moderator:
- Irgendwie sehe ich bei deinem SQL-Versuch nicht durch. Im WHERE vergleichst du die Daten von dst und src. src ist aber im SQL nirgends drin.
- max ist ein schlechter Name für ein Feld. Es ist auch ein SQL-Befehl. Beschreibe beim Feldnamen von was es das Max ist. zB max_val.
- Eine Tabelle ist beschrieben. Die Andere nicht. ebensowenig ihre Beziehnung zu einander
- Was hat es mit G1 bis G3 auf sich?
 
Hallo Y
Danke Dir für Deine rasche Antwort

- Irgendwie sehe ich bei deinem SQL-Versuch nicht durch. Im WHERE vergleichst du die Daten von dst und src. src ist aber im SQL nirgends drin.
dst und src ist die gleiche Tabelle sein.
dst soll die Zieltabelle für den update sein (Definiert in Zeile 1) und src die Quelltabelle für die Unterabfrage (Definiert in Zeile 8)

- max ist ein schlechter Name für ein Feld. Es ist auch ein SQL-Befehl. Beschreibe beim Feldnamen von was es das Max ist. zB max_val.
Ist ein sehr guter Hinweis. Werde ich sofort abändern. Das ist aber sicherlich nicht das Hauptproblem.
Ich habe zum Testen eine kl. Test- Tabelle (ATLANTIS) erstellt, in der ich trotz anderer Namen (ohne max) die gleichen Fehlermeldungen bekomme.

Dort ist in Analogie:
  • UPE_PK <> PK
  • Z_TLN <>G1
  • GUELTIG_AB <> G2
  • UPE_QUELLE <>G3
  • UPE <>VAL
  • MAX <>FLAG
- Was hat es mit G1 bis G3 auf sich?
Das war ein dummer Fehler. Satt des richtigen SQL Statements habe ich versehentlich das meiner Testtabelle (ATLANTIS) eingefügt. Damit habe ich jetzt grosse Verwirrung angerichtet.
"SELECT Max(src.VAL) FROM ATLANTIS src GROUP BY src."G1", src."G2", src."G3" funktioniert" muss heissen:
SELECT Max(src.UPE) FROM T_TRAD_UPE_SB src GROUP BY src."Z_TLN", src."UPE_QUELLE", src."GUELTIG_AB" funktioniert.


Kann ich das oben in der Originalanfrage noch irgendwie editieren, um niemanden mehr zu verwirren?

Ich hoffe somit ist dann klar, was ich überhapt haben möchte...

Gruss

Atlantis
 
Hallo Yaslav

Tolle Seite auf die Du verlinkt hast. Habe ich gleich als Lesezeichen abgelegt...
Ich bin mir nicht sicher, ob ich damit schon ans Ziel komme:
Wenn man bei Deiner Tabelle eine Spalte Maxkurs und die grünen Werte hinzufügt

[kurs]
w1 | w2 | kurs | datum | Maxkurs
CHF | EUR | 0.779438988 | 2011-03-21
CHF | USD | 1.10045 | 2011-03-20
CHF | USD | 1.10314 | 2011-03-21
CHF | EUR | 0.872367653 | 2011-03-20
CHF | USD | 1.10112 | 2011-03-19
CHF | EUR | 0.79 | 2011-03-21
CHF | EUR | 0.79 | 2011-03-21
CHF | USD | 1.12 | 2011-03-19


Jetzt möchte ich die Spalte Maxkurs per Update auf 1 setzen und zwar da, wo die Gruppe w1,w2,datum den Maxwert beim Kurs hat.
(Wunschergebnis in Blau)
[kurs]
w1 | w2 | kurs | datum | Maxkurs
CHF | EUR | 0.779438988 | 2011-03-21
CHF | USD | 1.10045 | 2011-03-20 1
CHF | USD | 1.10314 | 2011-03-21 1
CHF | EUR | 0.872367653 | 2011-03-20
CHF | USD | 1.10112 | 2011-03-19
CHF | EUR | 0.79 | 2011-03-21 1
CHF | EUR | 0.79 | 2011-03-21 1
CHF | USD | 1.12 | 2011-03-19 1


Wie kann ich jetzt die DS aus dieser Unterabfrage:
SELECT w1,
w2,
MAX(datum) AS max_datum
FROM kurs
GROUP BY w1,
w2
;
in mein Update maxkurs so integrieren, dass es auch mehrere DS (dunkelgrün) geben darf, die dann gekennzeichnet werden?
Ich hatte gehofft eine Subquerry zu bekommen, dass mir die PK´s der jeweiligen DS liefert, die die 1 bekommen...

Sorry, dass ich noch nicht am Ziel bin.... und danke Dir vielmals für die Geduld...
 
OK, Ich glaube ich verstehe jetzt was du willst.

Das könnte so aussehen
SQL:
update kurs k
set k.maxkurs = 1
where
  exists (
      select km.w1, km.w2, max(km.datum) as max_datum
      from kurs km
      group by km.w1, km.w2
      having k.w1 = km.w1 and k.w2 = km.w2 and k.datum = max(km.datum)
  )
Code:
W1  W2        KURS DATUM                MAXKURS
--- --- ---------- ----------------- ----------
CHF EUR .779438988 21.03.11 00:00:00          1
CHF USD    1.10045 20.03.11 00:00:00          1
CHF EUR .872367653 20.03.11 00:00:00           
CHF EUR .872367653 20.03.11 00:00:00           
CHF USD    1.10112 19.03.11 00:00:00           
CHF USD    1.10112 19.03.11 00:00:00           
CHF EUR        .79 21.03.11 00:00:00          1
CHF EUR        .79 21.03.11 00:00:00          1
CHF USD       1.12 19.03.11 00:00:00
 
Hallo Yaslaw

Du bist ja wie ein Orakel, das alles weis...
Ich zücke den Hut! Damit hast DU mir sehr geholfen!

Der Ansatz von Dir war zwar nicht wie von mir gewünscht, aber damit habe ich mir jetzt die Lösung selbst basteln können...

UPDATE kurs k
SET k.maxkurs = 1
WHERE
EXISTS (
SELECT km.w1, km.w2, MAX(km.KURS) AS max_kurs
FROM kurs km
GROUP BY km.w1, km.w2, km.datum
HAVING k.w1 = km.w1 AND k.w2 = km.w2 AND k.datum = km.datum AND MAX(km.kurs)
)

Jetzt noch Sahnehäubchen Frage:
Wenn ich alle anderen Datensätze auf 0 Setzen möchte, gibt es da einen kürzeren/ eleganteren und vor allem zeitlich schnellleren Weg als:

UPDATE kurs k
SET k.maxkurs = 1
WHERE
EXISTS (
SELECT km.w1, km.w2, MAX(km.KURS) AS max_kurs
FROM kurs km
GROUP BY km.w1, km.w2, km.datum
HAVING k.w1 = km.w1 AND k.w2 = km.w2 AND k.datum = km.datum AND MAX(km.kurs)

)

UPDATE kurs k
SET k.maxkurs = 0
WHERE
NOT EXISTS (
SELECT km.w1, km.w2, MAX(km.KURS) AS max_kurs
FROM kurs km
GROUP BY km.w1, km.w2, km.datum
HAVING k.w1 = km.w1 AND k.w2 = km.w2 AND k.datum = km.datum AND MAX(km.kurs)
)
So etwas wie die ELSE Funktion...

Und Danke noch einmal vielmals!

Atlantis
 
Bitte in Zukunft dein Code in Code-Tags schreiben. Macht ihn lesbarer.

Zu deiner Frage. Die Logik aus dem WHERE herausnehmen und in den Set einfügen. Mit CASE WHEN auswerten und 0 oder 1 zurückgeben.

SQL:
UPDATE kurs k
SET k.maxkurs = CASE WHEN EXISTS (
              SELECT km.w1
              FROM kurs km
              GROUP BY km.w1, km.w2, km.datum
              HAVING k.w1 = km.w1 AND k.w2 = km.w2 AND k.datum = km.datum AND MAX(km.kurs) = k.kurs
            )
        THEN 1
        ELSE 0
      END;
 
Hallo Yaslav

Kann es sein, dass die Abfrage von heute Morgen 8:55 Uhr (im SQL Developer gestartet) jetzt noch läuft bei 1.844.328 Datensätzen?
Eher nicht, oder? Fehlermeldung gab es zumindest keine...

Das war der Code:
SQL:
UPDATE T_TRAD_UPE_SB dst
SET dst.MAXWERT = case when
EXISTS (
           SELECT src.Z_TLN, src.GUELTIG_AB, MAX(src.UPE) AS MAX_VAL
           FROM T_TRAD_UPE_SB src
           GROUP BY src.Z_TLN, src.GUELTIG_AB, src.UPE_QUELLE
           HAVING dst.Z_TLN = src.Z_TLN AND dst.GUELTIG_AB = src.GUELTIG_AB AND dst.UPE = MAX(src.UPE)
           )
THEN 1
ELSE 0
END;
 
Zurück