tutorials.de Buch-Aktion 05/2012
Like Tree1Danke
  • 1 Beitrag von Thomas Darimont
ERLEDIGT
NEIN
ANTWORTEN
2
ZUGRIFFE
1229
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Avatar von mirscho
    mirscho mirscho ist offline Mitglied Brokat
    Registriert seit
    Mar 2002
    Ort
    Pößneck
    Beiträge
    284
    Halli Hallo!

    Ich habe folgende Tabelle fiktiv ausgedacht ( es sind viel mehr als 250000 Datensätze )

    ID+++++ART++++++GUELTIG_AB+++++++DATUM_TS+++++++ERGEBNIS
    100 ++++ IQ TEST+++++01.01.1901++++++1101201017562445++++++10
    100 ++++ SEHTEST+++++25.12.2009++++++2512200916362255++++++2-
    100 ++++ IQ TEST+++++11.02.2010++++++1102201016443317++++++13

    Ein kurze Erläuterung zu der Tabelle:

    Ich kann an der ganzen Datenbank NICHTS verändern! Nur abfragen!
    Es sind noch andere Felder vorhanden, welche hierfür aber keine Rolle spielen.
    Die Spalte DATUM_TS ist im TIMESTAMP Format. Die Spalte ID ebenso.
    Die Spalte ID dient als Verknüpfung zu einer Personentabelle.
    Die Spalte ERGEBNIS ist CHAR(4).
    In der Spalte GUELTIG_AB steht das Datum ab wann der Wert der Spalte ERGEBNIS gültig ist. Die Datumswerte von abgelaufenen Tests werden dann einfach mit "01.01.1901" aufgefüllt.

    Nun mein Problem:

    Ich möchte alle Personen abfragen welche beim letzten Sehtest einen Wert zwischen 10 und 15 hatten UND sich dieser Wert verschlechtert hat.

    Beispiel: Eine Person hatte erst 10 Punkte und jetzt 13. Dann soll diese Person in der Liste erscheinen.
    Eine Person hatte erst 11 Punkte und 16. Dann soll diese Person ebenfalls erscheinen.

    Welchen Daten sollen ausgegeben werden?
    • Daten aus der Personentabelle
    • Datum des letzten Tests
    • Testart
    • Ergebnis des Testes

    Ich habe schon einiges probiert (Nested Table, Subselect) doch komme ich nicht hin. Leider kann ich hier auch nichts an SQL einbinden, da der PC nicht am Internet ist.

    Ich danke schon mal im Voraus!
    Geändert von mirscho (11.03.10 um 16:53 Uhr)
     

  2. #2
    Avatar von Vereth
    Vereth Vereth ist offline Mitglied Brokat
    Registriert seit
    Nov 2009
    Ort
    Dortmund
    Beiträge
    372
    Ich habe hier eine Lösungsmöglichkeit für dich ausgeknobelt; ich hoffe, die Parameter in der WHERE-Klausel entsprechen deinen Wünschen. Notfalls kannst du sie aber leicht anpassen, denn eigentlich ist die Abfrage nicht schwer zu verstehen. Grundlage ist ein Equi-Join der Tabelle test mit sich selbst, um so die Werte der Spalte ergebnis zweimal zur Verfügung zu haben.
    Die Abfrage setzt voraus, dass für eine Person nur maximal zwei Datensätze mit Gültigkeitsdatum > 01.01.1901 vorhanden sind, sonst sind die Resultate nicht eindeutig.
    Code sql:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    SELECT p1.*, t1.datum_ts, t1.art, t1.ergebnis, t2.ergebnis
    FROM test t1, test  t2, person p1
    WHERE p1.id = t1.id
      AND t1.id = t2.id
      AND t1.art = t2.art
      AND t1.art = "Sehtest"
      AND t1.gueltig_ab > 01.01.1901
      AND t2.gueltig_ab > 01.01.1901
      AND t1.datum_ts > t2.datum_ts
      AND t2.ergebnis >= 10
      AND t2.ergebnis <= 16
      AND t1.ergebnis > t2.ergebnis
    Obwohl die Vorgehensweise im Prinzip funktionieren dürfte, rate ich aus Performancegründen davon ab. Ich persönlich würde lieber einen passenden Datenbankauszug in eine Textdatei erstellen und diese mit einem Programm oder awk-Skript auswerten; das dürfte wahrscheinlich schneller und sicherer sein als ein Equi-Join über 250.000 Datensätze.

    ACHTUNG: Anwendung auf eigene Gefahr. Der Autor übernimmt keine Haftung für z.B. Rechnerabstürze wegen Speichermangels oder Prozessorüberlastung.
     
    Vielen Dank für die Nutzung des Bewerten- und Danke-Buttons

    Wenn man sieht, dass man einen anderen glücklich gemacht hat, ist die Welt um zwei glückliche Menschen reicher.

  3. #3
    Registriert seit
    Jun 2002
    Ort
    Saarbrücken (Saarland)
    Beiträge
    9.886
    Blog-Einträge
    29
    Hallo,

    interessante Fragestellung Habs gerade mal nachgespielt.
    Wenn db2 die von Oracle bekannten analytischen Funktionen lead / lag kennen würde
    könnte man das Problem damit recht einfach lösen.

    Leider gibt es diese Funktionen so nicht direkt in DB2 aber man kann sich die
    Funktionalität auch selber bauen, in dem man eine Aggregatsfunktion mit entsprechender
    over / partition-Klause verwendet.

    Zur Lösung habe ich mit max(xxx) over (partition by ...) gearbeitet und somit die Oracle-Funktion lag
    emuliert.

    Unsere Tabelle test_records:
    Code sql:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    CREATE TABLE "DB2ADMIN"."TEST_RECORDS"  (
              "ID" BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY (  
                START WITH +0  
                INCREMENT BY +1  
                MINVALUE +0  
                MAXVALUE +9223372036854775807  
                NO CYCLE  
                NO CACHE  
                NO ORDER ) , 
              "USERID" BIGINT NOT NULL , 
              "KIND" VARCHAR(32) NOT NULL , 
              "VALID_FROM" BIGINT NOT NULL , 
              "SCORE" BIGINT NOT NULL )   
             IN "USERSPACE1" ;

    Unsere Inserts:
    Code sql:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    INSERT INTO DB2ADMIN."TEST_RECORDS" (userid,kind,valid_from,score) VALUES (1,'sehtest',20010101,12);
    INSERT INTO DB2ADMIN."TEST_RECORDS" (userid,kind,valid_from,score) VALUES (1,'sehtest',20010103,15);
    -- Verschlechterung
    INSERT INTO DB2ADMIN."TEST_RECORDS" (userid,kind,valid_from,score) VALUES (1,'sehtest',20010110,13); 
     
    -- Nur 1 Satz -> Keine Verschlechterung
    INSERT INTO DB2ADMIN."TEST_RECORDS" (userid,kind,valid_from,score) VALUES (2,'sehtest',20010101,6);
     
    INSERT INTO DB2ADMIN."TEST_RECORDS" (userid,kind,valid_from,score) VALUES (3,'sehtest',20010101,7);
    INSERT INTO DB2ADMIN."TEST_RECORDS" (userid,kind,valid_from,score) VALUES (3,'sehtest',20010102,10);
    -- Verschlechterung
    INSERT INTO DB2ADMIN."TEST_RECORDS" (userid,kind,valid_from,score) VALUES (3,'sehtest',20010103,9);
     
    INSERT INTO DB2ADMIN."TEST_RECORDS" (userid,kind,valid_from,score) VALUES (4,'sehtest',20010101,3);
    INSERT INTO DB2ADMIN."TEST_RECORDS" (userid,kind,valid_from,score) VALUES (4,'sehtest',20010102,5);
    INSERT INTO DB2ADMIN."TEST_RECORDS" (userid,kind,valid_from,score) VALUES (4,'sehtest',20010103,2);
    -- Verbesserung
    INSERT INTO DB2ADMIN."TEST_RECORDS" (userid,kind,valid_from,score) VALUES (4,'sehtest',20010104,11);

    Daten:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    ID;USERID;KIND;VALID_FROM;SCORE
    26;1;"sehtest";20010101;12
    27;1;"sehtest";20010103;15
    28;1;"sehtest";20010110;13
    29;2;"sehtest";20010101;6
    30;3;"sehtest";20010101;7
    31;3;"sehtest";20010102;10
    32;3;"sehtest";20010103;9
    33;4;"sehtest";20010101;3
    34;4;"sehtest";20010102;5
    35;4;"sehtest";20010103;2
    36;4;"sehtest";20010104;11

    Code sql:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    SELECT 
        t.id
        ,t.userid
        ,t.kind
        ,t.valid_from
        ,t.current_score
        ,t.previous_score
    FROM 
    (
        SELECT 
              id
            , userid
            , kind
            , valid_from
            , score current_score
            , MAX(score) OVER (partition BY userid ORDER BY valid_from ASC ROWS BETWEEN 1 preceding AND 1 preceding) previous_score 
            , MAX(valid_from) OVER (partition BY userid) latest_valid_from
        FROM 
            DB2ADMIN."TEST_RECORDS"
    ) t
    WHERE 
        t.current_score < t.previous_score 
        AND t.valid_from = t.latest_valid_from
    ORDER BY 
          t.userid
        , t.valid_from

    Ausgabe:
    Code :
    1
    2
    3
    
    ID;USERID;KIND;VALID_FROM;CURRENT_SCORE;PREVIOUS_SCORE
    28;1;"sehtest";20010110;13;15
    32;3;"sehtest";20010103;9;10
    User 2 ist nicht dabei da es dafür nur einen Eintrag gibt -> keine Verschlechterung
    User 4 hat beim letzten Test eine Verbesserung geschafft.

    Gruß Tom
    Vereth bedankt sich. 
    Java rocks!
    How to become a good Java Programmer?
    Does IT in Java and .Net
    The only valid measurement of code quality: WTFs / minute
    Blog
    Xing
    Twitter

Ähnliche Themen

  1. Antworten: 5
    Letzter Beitrag: 02.06.10, 12:52
  2. Antworten: 11
    Letzter Beitrag: 26.06.08, 19:49
  3. mehrere Werte in eine Spalte
    Von maxikey im Forum PHP
    Antworten: 5
    Letzter Beitrag: 11.05.08, 21:08
  4. Antworten: 6
    Letzter Beitrag: 04.06.05, 17:15
  5. Werte einer Tabelle durch Werte anderer Tabelle ersetzen
    Von Oremliac im Forum Relationale Datenbanksysteme
    Antworten: 1
    Letzter Beitrag: 28.01.04, 21:21