Neuigkeiten:

Ist euer Problem gelöst, dann bitte den Knopf "Thema gelöst" drücken!

Mobiles Hauptmenü

Datenbank bereinigen

Begonnen von ulmilten, Oktober 08, 2016, 16:25:38

⏪ vorheriges - nächstes ⏩

ulmilten

Hallo,
ich habe folgende Frage. Ich hab eine große Datenbank, dort sind ganz viele verschiedene ISINs gespeichert. Zu den ISINS werden werden noch Werte gespeichert, mehrmals am Tag. Nun möchte ich eine Abfrage erstellen, dass er mir für jeden Tag, wo die ISIN gespeichert wurde, nur noch den letzten Datensatz zur Verfügung stellt, der Rest soll endgültig GELÖSCHT werden.

So sieht sie exemplarisch für eine ISIN aus. Man muss also irgendwie aus dem TimeStamp erst den Tag ziehen, dann für jeden Tag alles bis auf die letzte Zeit löschen und das für jede ISIN.

Wie sieht die DELETE Anweisung aus? Schon mal vielen Dank.



crystal

Hallo,
hier ein erster Ansatz:

DELETE * FROM <tabelle>
WHERE <datum> = "datum"
AND Id IN
(SELECT Id FROM <tabelle>
WHERE Id NOT IN
(SELECT TOP 1 Id
FROM <tabelle>
WHERE <datum> = "datum"
ORDER BY Id DESC));

ACHTUNG: nicht ausführen, erst testen.

Idee: den letzten Datensatz des Tages mit "TOP 1" (absteigende Sortierung) selektieren und dann alle Datensätze löschen, die nicht in dieser Abfrage enthalten sind (NOT IN).

Aber:
1. Performance ist eher schlecht, weil der NOT-IN-Vergleich für jeden DS ausgeführt werden muss.
2. Ich hab's nur mit dem SELECT-Part probiert (ohne DELETE FROM).
3. <datum> muss gesetzt weden. Die Syntax für "datum" ist hier im Forum beschrieben. Woher du das Datum bekommst, geht aus deinem Beispiel nicht hervor.
4. Nenne Tabellenspalten nie einfach nur "Id", sondern immer z.B. <tabelle>_Id
5. Einfacher wäre es, alle Daten bis auf den Vortag zu löschen.
6. Wie viele Datensätze fallen pro Tag an? Wenn es seeehr viele sind, wird deine "Id" bald überlaufen. Dann müsstest du auf eine Replikations-Id umstellen oder die Id "irgendwie zurücksetzen", was etwas kompliziert wäre. Schau dir mal den Wertebereich für long integer an.
7. Bist du sicher, dass du auf die alten Daten verzichten kannst?
8. Warum brauchst du den letzten Eintrag des Vortages? Für das Hochzählen der 'Id' verwendet Access eine interne Tabelle.
9. Kaum jemand wird wissen, was ISIN bedeutet.

Warte ab, was andere Forums-Mitglieder zu deiner Frage noch sagen.

Schönen Sonntag,
crystal


Wer Fehler in meinen Antworten findet, darf sie behalten, muss sie aber kommentieren. ;-)
Dies ist keineswegs arrogant gemeint, sondern soll nur unterstreichen, dass meine Antworten - natürlich - nicht immer fehlerfrei sind und sein können.
Devise: bitte immer erst selbst probieren!

Aus gesundheitlichen Gründen nur noch selten dabei...

ulmilten

Erstmal hallo, danke fürs Kopfzerbrechen ;)

Wegen Performance mach ich mir ehrlich gesagt keine großen Gedanken, da ja nach nach dem ersten Ausführen schon mal 90% der Daten rausfliegen und Rechenpower vorhanden ist, dazu geht ja mit MS Access alles total schnell.

Das Datum wollte ich aus der Spalte "Timestamp" ziehen, da es ja dort hinterlegt ist.

Über 4. habe ich mir ehrlich gesagt nie Gedanken drüber gemacht :(

Bei 5. ein klares ja, das kann alles weg, der letzte Eintrag pro Tag reicht, der Rest juckt nicht mehr weiter.

Den letzten Eintrag des Vortages brauche, falls man nochmal den ungefähren Verlauf nachschauen muss, sonst hätte ich ja immer alles für jede ISIN bis auf den neuesten Eintrag löschen können.
ISIN sind übrigens die Codes, mit dem man an der Börse Wertpapiere eindeutig indentifizieren kann.


ebs17

DELETE
FROM
   TabelleX AS A
WHERE
   EXISTS
      (
         SELECT
            NULL
         FROM
            TabelleX AS B
         WHERE
            DateValue(B.Timestampfield) = DateValue(A.Timestampfield)
               AND
            B.ISIN = A.ISIN
               AND
            B.ID > A.ID
      )

Timestamp ist in Unterscheidung zu vielen anderen diskutierten reservierten Worten wirklich nicht als Bezeichnung eines Tabellenfeldes zu gebrauchen. Versuche zur Probe eine Anfügeabfrage, wo Timestamp als Feldname für die Zieltabelle vorkommt.
Mit freundlichem Glück Auf!

Eberhard

ulmilten

Vielen Dank auch Dir :)

Ja, das mit Timestamp als Name ist Murks..

Eine Frage. Warum vergleichst du die ID mit einem Größervergleich und nicht die Zeiten, um den letzten Eintrag vom Tag heraus zu bekommen?


ebs17

Ich ging davon aus, dass die ID's chronologisch erzeugt wurden und dass es da eine höhere Wahrscheinlichkeit gibt, dass da ein Index besteht. Der Timestampvergleich wäre aber wie vermutet sicherer.
Mit freundlichem Glück Auf!

Eberhard

ulmilten

Was haltet ihr hier von:


                       
DELETE FROM Tabelle t1
WHERE t1.Timestamp != (
SELECT MAX(t2.Timestamp)
FROM Tabelle t2
WHERE Datum(t1.Timestamp) = Datum(t2.Timestamp)
AND t1.ISIN = t2.ISIN
)


So in der geschachtelten Abfrage checke ich ja immer nur das Datum und lösche alles bis auf den letzten Eintrag.. Umgehe ich so das Problem und ist die Abfrage effektiv?

ebs17

Wagst Du es, Deine Variante auszuprobieren?

Anscheinend nicht, lieber willst Du diskutieren. Da solltest Du im Vorfeld mitteilen, in welchem SQL-Dialekt Du Dich bewegst. Jet-SQL (Access) ist das nicht.
Mit freundlichem Glück Auf!

Eberhard

ulmilten

Doch, ich probiere es gleich aus... Hatte nur gestern keinen Zugriff auf die Datenbank.

Und doch, es ist Access, hab mich bei dem Code an einem Internetbeispiel grob orientiert, das war wohl der Fehler

ulmilten

Also Hut ab ebs 17, habe deinen Code zu 95% übernommen und es klappte einwandfrei, durch die bin ich 1,3 Millionen überflüssige Einträge losgeworden :)

Habe jedoch ganz unten in deiner letzten Zeile B.ID > A.ID ersetzt durch
B.TimeStamp > A.Timestamp. Dies funktioniert ja auch, da er schon im richtigen Tag drin ist. War mir irgendwie sicherer...

Hauptproblem ist also gelöst, kann mich gar nicht genug bedanken.

Nun noch eine kleine Ergänzungsfrage, wollt ich ungern ein neues Thema zu aufmachen.

Ich füge ja in diese große Datenbank (Historie) Datensätze ein, die in einer anderen Datenbank sind und nach AktuellerTag-30Tage in die Historie verschoben sollen. Normalerweise macht man es ja so:

INSERT INTO AbsatzHist SELECT * FROM AbsatzCurrent WHERE AbsatzCurrent.TimeStamp < date()-30;

Problem ist nur, das geht ja nicht, weil in der neuen Tabelle ja die Einträge eine ID haben und in der Historischen auch, die kollidieren also.
Wie schreib ich es um, dass er bei den Daten, die er in die historische Tabelle rüberziehen soll, statt der ursprunglichen ID nun eine neue zuteilt, nämlich die erste freie (Max ID von der Historischen +1?) und den Datensatz so weiterführt...

ebs17

Das würde man so nur hinbekommen, wenn Du die Datensätze einzeln und somit in Serie überträgst.
Sinnvoller ist, in der Historientabelle einen Autowert für die ID zu führen. In der Anfügeabfrage verwendest Du dann die Feldlisten statt * und lässt die ID dabei weg.
Mit freundlichem Glück Auf!

Eberhard

ulmilten

Ja, so in der Art habe ich es mir auch überlegt.
Statt Select * alles außer die ID übertragen und in der Historydatenbank dann die ID als Primärschlüssel und als Autowert. Hatte leider heute keine Zeit mehr für, ich schaff es Donnerstag wieder mich mit zu beschäftigen.

Werd mich dann wieder hier melden, aber echt vielen Dank für deine Hilfe