locked
benötige hilfestellung für ein sql-konstrukt RRS feed

  • Frage

  • hay füxe;

    da ich mit dem SQL-zeuchs noch immer auf kriegsfuss stehe, will ich mal nachfragen, mit welcher abfrage ich bestimmte datensätze selektieren kann.

    zwei DBF's auf unterschiedlichen PC's, die nur sporadisch kommunizieren können. als änderungskriterium habe ich das feld "TimStmp"(=DateTime())

    zur zeit stolpere ich so durch alle datensätze und vergleiche jeweils die felder "Vorfall"+"TimStmp", was natürlich bei ein paar zigtausend sätzen lange braucht.

    ich will somit die datensätze per SELECT * FROM aus der tabelle "Ext_Data" in einen cursor laden, dessen Datensatz entweder in "Loc_Data" nicht vorhanden ist, oder "Ext_Data.Vorfall == Loc_Data.Vorfall .and. Ext_Data.TimStmp > Loc-Data.TimStmp" ist.

    kann man das überhaupt mit SQL erreichen?

    index ist keiner vorhanden.

    lg mike

     

    Dienstag, 7. September 2010 22:51

Alle Antworten

  • Hallo Mike,

    wenn Du Daten aus einer Tabelle selektieren möchtest, die in einer anderen Tabelle nicht enthalten sein sollen, dann sieht das in etwa wie folgt aus:

    select feld1, feld2, feld3, usw.
    	 from <tabelle> 
    	 where feld1 not in 
    	 (
    	 select feldx
    	 from <anderetabelle> 
    	 where feldx = y 
    	 )
    


    Gruss / Best regards -Tom 010101100100011001010000011110000101001001101111011000110110101101110011
    Mittwoch, 8. September 2010 06:27
  • Du willst den lokalen Satz eines Vorfall, den externen, wenn kein lokler da ist und den neueren von beiden, wenn der Vorfall in beiden existiert. Ich nehme zusätzlich mal an in beiden Tabellen könnte ein Vorfall mehrfach vorkommen hat aber jeweils einen neuesten Satz.

    Das heißt Du brauchst pro Vorfall nur den Datensatz mit Max(TimStmp). Die ganzen unterschiedlichen Fälle, wo ein oder mehrere Datensätze existieren kann Dir egal sein, wenn Du zuerst ein Union aller Sätze bildest und davon jeweils gruppiert nach Vorfall den Satz mit dem maximalen Timestamp selektierst.

     

    Select tempalias.Vorfall, Max(tempalias.TimStmp) as TimStmp;
    From
    (Select Vorfall, TimStmp From loc_data;
    Union;
    Select Vorfall, TimStmp From ext_data) tempalias;
    into Cursor curTmpResult Nofilter
    
    Select loc_data.* from loc_data;
    inner join curTmpResult on;
    loc_data.Vorfall = curTmpResult.Vorfall;
    and;
    loc_data.TimStmp = curTmpResult.TimStmp;
    Union;
    Select ext_data.* from ext_data;
    inner join curTmpResult on;
    ext_data.Vorfall = curTmpResult.Vorfall;
    and;
    ext_data.TimStmp = curTmpResult.TimStmp;
    Into Cursor curResult
    

    Wenn das Gesamtergebnis nach Vorfall sortiert werden soll Order By 1 Into Cursor curResult, sofern Vorfall das 1. Feld ist.

    • Als Antwort markiert Mike-Ao Mittwoch, 8. September 2010 22:03
    • Tag als Antwort aufgehoben Mike-Ao Mittwoch, 8. September 2010 22:04
    Mittwoch, 8. September 2010 07:45
  • "index ist keiner vorhanden."

    Warum der Geiz an Bytes bzw. diese Großzügigkeit mit der Zeit? Selbst in Scanschleifen wäre eine Sortierung nach Vorfall und TimStmp doch angenehm zur Auffindung des jeweils aktuellsten Datensatzes.

    Index on Vorfall tag Vorfall

    Index on TimStmp tag TimStmp

    auf beiden DBFs beide Index Kommandos einmal anwenden und gut.

    Tschüß, Olaf.

    • Als Antwort markiert Mike-Ao Mittwoch, 8. September 2010 22:03
    • Tag als Antwort aufgehoben Mike-Ao Mittwoch, 8. September 2010 22:04
    Mittwoch, 8. September 2010 07:50
  • hi olaf;

    danke für das gerüst.

    bei'm ersten select mosert der fux herum, dass eine GROUP BY fehlt. damit fange ich schon mal gar nix an :-(

    wenn ich dem ding dann vorm "INTO CURSOR" ein "GROUP BY Vorfall" verpasse, dann hab ich zwar mal eine tabelle, aber im zweiten select will er Vorfall irgendwie als UNIQUE haben. und da liege ich mit meinem SQL-wissen schon 6fuss tiefer...

    aber der erste select braucht bei rd. 10000 sätzen 0,75 sec. wenn ich ein klassisches

        SELECT * FROM EXT_Data INTO CURSOR Ext_Temp ORDER BY TimStmp DESC

    mache, brauche ich nur 0,58sec (netzwerk)

    ich glaub, ich bleibe doch bei der alten version, indem ich dann mich satz für satz durchhangle, bis ich identische Vorvall+TimStmp finde

    immerhin werden keine daten "geuploadet", sondern immer vom anderen rechner "gedownloadet". das kommt daher, dass auch VPN verwendet werden soll, und ich keine zerschossenen tabellen wegen netzunterbrechung haben will.

    btw. er Vorfall-verteiler ist nur eine kopfdatei, in der nur die basisdaten eingetragen sind (vorfallnummer, vorfalltype, summen der einzelnen leistungen, memo als protokoll des bearbeitungsablaufes, rechnungs- und bearbeitungsadresse)

    die restlichen daten sind in einigen anderen tabellen hinterlegt, die erst dann geholt werden, wenn sich TimStmp des verteilers geändert hat.

    die "knausrigkeit" eines fehlenden index beruht darauf, da es immer noch fremdprogramme gibt, die einen neuen vorfall eintragen können, aber keine ahnung haben, wie man z.b. eine CDX aktualisiert.

    lg mike

     

    Donnerstag, 9. September 2010 02:16
  • Hallo Mike,

    das ganze Problem lässt sich mit folgendem SQL-Konstrukt erschlagen:

    SELECT * FROM ext_data WHERE vorfall NOT IN (SELECT vorfall FROM loc_data) ;
    UNION SELECT a.* FROM ext_data a INNER JOIN loc_data b ON a.vorfall=b.vorfall WHERE a.timstmp>b.timstmp ;
    UNION SELECT b.* FROM ext_data a INNER JOIN loc_data b ON a.vorfall=b.vorfall WHERE a.timstmp<=b.timstmp
    

     

     

     

    Der erste Select holt die neuen Vorfälle, im zweiten werden die extern aktualisierten Vorfälle behandelt und der dritte Select holt die nicht geänderten Datensätze aus loc_data.
    Wie Olaf schon schrieb, solltest Du aber durchaus nicht mit Indizes geizen.

    Gruß Andreas

    Donnerstag, 9. September 2010 05:43
  • Hallo Mike,

    Sorry für das fehlende Group By, klar, wenn ich Max(tempalias.TimStmp) as TimStmp selektiere meine ich das pro Vorfall. Du kannst trotz externer Programme mit CDX arbeiten, allerdings muß der CDX dann im ersten Schritt mal über die vollen Daten aufgefrischt werden und das kommt dann natürlich zur Zeit dazu.

    Allerdings kennt selbst FP2.6 cdx, nur idx werden nicht automatisch aufgefrischt, CDX immer, auch wenn andere Programme die Indizes ansonsten nicht kennen oder nutzen. Außer das ist dann dbase, clipper oder irgendeine dbf-Implementation für PHP, Perl etc. was es da so gibt und nicht vollständig ist.

    Wenn Du nur mal Fehlermeldungen vollständig bringen würdest. Wegen "unique" nehme ich an, daß im zweiten SQL angemeckert wird, daß ein Feld nicht eineindeutig benannt wird. Wenn Du statt wie ich ext_data.Vorfall z.B. nur Vorfall schreibst, weiß VFP nicht, von welcher Tabelle das Vorfall Feld gemeint ist. Ich habe was das angeht aber in dem SQL immer explizit Tabellenname.Feldname genommen, oder? Andreas Berger hat da schon eine gute Idee. Ich würde nur Konstrukte wie NOT IN (SQL) vermeiden, weil ich meine, die sind weniger gut optimierba, aber ist reine Gefühlssache.

    Tschüß, Olaf.

    Samstag, 11. September 2010 12:15
  • hi olaf;

    danke für den fehlenden hinweis; werd mir diesen mechanismus nochmal durchkauen, in der hoffnung, dass ich solche verschatelten SQL'dingsbumser auch mal kapier (schäm-grins)

    abba ich hab noch eine frage zur kollissionsmöglichkeit im lokalen netz, wenn ich einen neuen vorfall erstellen möchte und zwei mitarbeiter kloppen zum gleichen zeitpunkt auf den button [neuer Vorfall]

        USE (Quelle) ALIAS Q_Alias IN 0 SHARED AGAIN
        INSERT INTO Q_Alias (VfNUMM, VfGRUP, VfSUBN, VfUser, TIMSTMP) ;
            SELECT TOP 1 TRANSFORM(VAL(VfNUMM)+1,"@L "+REPLICATE("9",LEN(VfNUMM))), ;
                        PAR_VfGRUP, ;
                        REPLICATE("0", LN_VfNUMM), ;
                        SYS(0), ;
                        DATETIME() ;
            FROM Q_Alias ;
            ORDER BY VfNUMM DESC ;
            WHERE AT(VfGRUP,"KLVBF")#0

    externe PC's bekommen ja immer einen nummernblock (pool) vorgegeben, der wie am threadanfang abgeglichen und danach wieder gefüllt wird. lokale, direkt am server arbeitende mitarbeiter beötigen keine vorbelegung, daher kann der MA sich die nächste laufende VfNUMM sofort erstellen lassen.

     


    Freitag, 17. September 2010 02:10
  • hi olaf und andreas;

    in beiden vorschlägen bekomme ich die fehlermeldung

    "Operation is invalid for Memo Blob General or Picture field"

    ich habe nur normale text, datum oder datetime-felder ?!?

     

    lg mike

    Sonntag, 19. September 2010 02:32
  • Hallo Mike,

    Du wirst wohl doch ein Memo-Feld in Deinen Tabellen haben. Die UNION-Klausel ist die Ursache für die Fehlermeldung:

    VFP-Hilfe: "When one of the columns is of Memo, General, or Blob type, performing unions of differing column types is not allowed."

    In diesem Fall bleibt Dir noch die Möglichkeit, die UNIONS händisch auszuführen.

    SELECT * FROM ext_data WHERE vorfall NOT IN (SELECT vorfall FROM loc_data) INTO CURSOR cur1 READWRITE

    SELECT a.* FROM ext_data a INNER JOIN loc_data b ON a.vorfall=b.vorfall WHERE a.timstmp>b.timstmp INTO CURSOR cur2

    SELECT b.* FROM ext_data a INNER JOIN loc_data b ON a.vorfall=b.vorfall WHERE a.timstmp<=b.timstmp INTO CURSOR cur3

    SELECT cur1

    APPEND FROM DBF("cur2")

    APPEND FROM DBF("cur3")

    BROWSE

    Gruß Andreas

     

    Montag, 20. September 2010 05:48
  • Bezüglich Deiner Nummervergabe:

    USE (Quelle) ALIAS Q_Alias IN 0 SHARED AGAIN 


    INSERT INTO Q_Alias (VfNUMM, ...
    SELECT TOP 1 ... FROM Q_Alias 

    Irgendwie kann da doch was nicht angehen. Du selektierst dann aus derselben Tabelle, in die Du anfügst.

    Es gibt doch die newid Funktion in der newid-Beispieldatenbank, mach nicht so einen Murks, ein Select MAX oder TOP1 greift doch auch erst einmal nur eine ID lesend ab und sperrt oder löscht Sie nicht gleichzeitig, das fehlt in Deinem Code dann völlig. 

    Tschüß, Olaf.

    Dienstag, 21. September 2010 07:34
  • hi olaf;

    danke für den hinweis.

     

    hab da noch ein anderes problem.

    Ich gebe eine PLZ (=Par_OrtPLZ) vor. nun möchte ich die der PLZ entsprechenden Ortsnamen, Vorwahl etc. als UNIQUE, aber nach TIMSTMP DESC sortiert erhalten. natürlich ist TIMSTMP nie gleich. mit dem folgenden SELECT habe ich zwar alle Ort-Eigenschaften erhalten, aber nicht nach der aktuellsten (TIMSTMP) reihenfolge

     

    SELECT DISTINCT OrtName, OrtVorwahl, ... FROM SrcFile ;

        INTO CURSOR (C_Alias) ;

        WHERE OrtPLZ == Par_OrtPLZ ;

        ORDER BY TIMSTMP DESC

     

    lg mike

     

    Sonntag, 26. September 2010 14:16