PQ: Table.Join liefert sowas wie ne Kreuztabelle - warum?
#1
Hallo Ihr Wissenden,

derzeit arbeite ich an einer Aufgabe, aus einem Verzeichnis bestimmte Dateien (alles ASCII) zu laden, Daten daraus zu extrahieren und alles in einer Tabelle gesammelt zur Verfügung zu haben (nachfolgend: die "Sammlung").
Es handelt sich dabei um derzeit über 11000 Dateien, die den Kriterien formal genügen.
Da ständig neue Dateien hinzukommen (werktäglich durchaus auch schon mal >10), gehe ich so vor, dass ich sowohl den aktuellen Dateibestand in PQ abfrage (--> Zugriff auf das Netz-Laufwerk), als auch die schon ausgewerteten Dateien aus der Sammlung einlese (--> Zugriff auf die XL-Tabelle). Anschließend vergleiche ich die beiden Tabellen und nur für die Dateien, die neu hinzugekommen sind, führe ich die Funktion aus, den Dateiinhalt jeweils auszulesen und in die Tabelle einzufügen (sonst müsste ich das jedes Mal für die 11000+ Dateien machen, bald sind's 12000). Soweit zur Ausgangslage.

Um vergleichen zu können:
  • führe ich einen Table.Join auf 
  •    einerseits das Ergebnis der Verzeichnisabfrage und
  •    andererseits das Ergebnis der Sammlungsabfrage durch 
  •    mit dem Schlüsselfeld "Dateiname" --> das klappt auch soweit problemlos
  • füge eine weitere Spalte "Vergleich" an, in der ich jeweils 1 (falls neu) oder 0 (schon bekannt) eintrage ("Gesamttabelle", "zu teilende Tabelle")
  • teile die Tabelle auf in eine "Neu" --> muss zerlegt werden (d.h. in der Spalte "Vergleich" steht 1) und eine "Alt", mit der erst mal nix mehr passieren muss
  •     diese Aufteilung via Table.SelectRows(, each ([Vergleich] = 1)
  • und füge nach Zerlegung der neuen letztendlich beide Tabellen wieder zusammen, bevor die Sammlung in der XL-Tabelle aktualisiert (d.h.: überschrieben) wird
soweit hierzu.

Für die Aufteilung in "Neu" und "Alt" dachte ich mir nun, dass es doch effizienter sei, zwei Tabellen mit jeweils derselben Anzahl an Zeilen wie die Gesamttabelle zu erzeugen, aber nur einer Spalte mit überall 1 resp. 0.
Mit einem Table.Join( , "Vergleich", , "Column1", JoinKind.LeftOuter) füge ich nun meine "1"-Tabelle und die zu teilende Tabelle zusammen --> das sollte meiner Erwartung nach nur die Zeilen übrig lassen, die in der zu teilenden Tabelle in der Vergleichsspalte auch = 1 sind. (Die o.g. Alternative tut's - aber die Vermutung war, da es sich beim Table.Join um eine 'native' Datenbankoperation handelt, dass das effektiver sei als in allen 11000+ Zeilen den 'händischen' Vergleich auszuführen)
Nun erhalte ich aber statt der erwarteten Aufspaltung eine völlig unübersichtliche Art Kreuztabelle - keine Ahnung, warum.
Kann mir jemand hier 'auf die Sprünge helfen' ?
Nachfolgend der relevante Auszug aus dem PQ-Script:
Code:
// in der Tabelle "Neu+Alt" sind Laufwerk-Abfrage und Tabellen-Abfrage 'ge-Joint'
//  nun die Vergleichs-Spalte bilden für Alt gegen Neu
//  (Datei-Datum hat mehr als 1 Sekunde Unterschied (d.h. die Datei wurde zwischenzeitlich verändert) oder
//  der Dateiname (aus dem Laufwerk) hat keine Entsprechung in der XL-Tabelle)
    Vergleich = Table.AddColumn(#"Neu+Alt", "Vergleich", each if
        (Number.Abs(Number.From([DateiDatum]-[ModifyDateandTime]))>1/24/3600 or [Name]=null)
        then 1 else 0),
    ZeilenZahl = Table.RowCount(Vergleich),                   //Anzahl aller Einträge der Vergleichs-Tabelle
    ZeilenZahl2Modify=List.Sum(Vergleich[Vergleich]),         //Anzahl der Neu-Einträge
    ZeilenZahlAlt=ZeilenZahl - ZeilenZahl2Modify,             //Differenz=Anzahl vorhandener Einträge
// es wird aus der Spalte mit Dateinamen (aus Laufwerk) und der Spalte Namen (aus XL-Tabelle) eine neue Spalte "Namen" gebildet
// für die spätere Verwendung       
   NamenZusammenfügen = Table.RenameColumns(
        Table.RemoveColumns(
           Table.AddColumn(Vergleich, "Name1", each
              try if Text.Length([Name])>0 then [Name] else [DateiName] otherwise [DateiName]),
        {"Name"}),
        {{"Name1","Name"}}),
//Die "1"-Tabelle
    ListeMit1=List.Buffer(List.Repeat({1},ZeilenZahl)),     //Eine Liste mit "1" zum schnelleren Extrahieren der zu bearbeitenden Dateien per Table.Join
    TabelleMit1 = Table.Buffer(Table.FromList(ListeMit1, Splitter.SplitByNothing(), null, null, null)),
//Die "0"-Tabelle
    ListeMit0 = List.Buffer(List.Repeat({0},ZeilenZahl)),   //Eine Liste mit "0" ... um die bestehenden Dateien zu ermitteln per Table.Join
    TabelleMit0 = Table.Buffer(Table.FromList(ListeMit0, Splitter.SplitByNothing(), null, null, null)),
//Die Liste noch zu bearbeitender Dateien
// Variante 1 mit Table.Join
    TabOffen=Table.Join(ZeilenZahl,"Vergleich",TabelleMit1,"Column1", JoinKind.LeftOuter),
// Variante 2 "klassisch"
    zuBearbeiten = Table.SelectRows(NamenZusammenfügen, each ([Vergleich] = 1)),


Gruß und Dank,
RaiSta
Antworten Top
#2
Hallo,

bevor es PQ gab, konnte so eine Aufgabe mit

- Markieren der bereits bearbeiteten Datei z.B. mit Attribute +r (ReadOnly)
- Liste der Dateien in einem weiteren Sheet

Das dürfte einfacher sein als ein "Table-Join"

mfg
Antworten Top
#3
Anstatt eines Tabellenjoins (Inhalt Verzeichnis alt mit Inhalt Verzeichnis Neu) durchzuführen, kann du auch die neuen Dateinamen and die alten anfügen, gruppieren und dabei zählen. Die mit einer "1" sind neu und somit müssen deren Daten importiert werden.
Antworten Top
#4
(30.08.2022, 13:01)Fennek schrieb: bevor es PQ gab, konnte so eine Aufgabe mit

- Markieren der bereits bearbeiteten Datei z.B. mit Attribute +r (ReadOnly)
- Liste der Dateien in einem weiteren Sheet

Das dürfte einfacher sein als ein "Table-Join"

Das versteh' ich jetzt nicht so ganz... Es geht darum, ein Verzeichnis laufend(!) zu überwachen, d.h., dass die Auswertung immer wieder wiederholt wird.
Manuell dann bei >11000 Dateien das Attribut zu ändern (aber auch nur bei bestimmten im Verzeichnis) erscheint mir nicht praktikabel. Ebenso, warum das 'einfacher sein sollte als ein Table.Join' erschließt sich mir irgendwie nicht - das Join kann PQ schon ganz gut und geht auch vergleichsweise schnell.

Oder, habe ich Dich falsch verstanden?

Gruß und Dank,
RaiSta

(30.08.2022, 13:35)ws-53 schrieb: Anstatt eines Tabellenjoins (Inhalt Verzeichnis alt mit Inhalt Verzeichnis Neu) durchzuführen, kann du auch die neuen Dateinamen and die alten anfügen, gruppieren und dabei zählen. Die mit einer "1" sind neu und somit müssen deren Daten importiert werden.

Hmmm, das mit dem Gruppieren - muss ich noch mal durchdenken. Allerdings ist es ja nicht nur so, dass neue Dateien dazu kommen, sondern auch schon bearbeitete zwischenzeitlich noch mal überarbeitet wurden, somit erneut analysiert werden müssen. Daher vergleiche ich auch auf Dateidatum früher und jetzt um mehr als 1 Sekunde unterschiedlich.

Außerdem erhalte ich mit meiner Methode ja auch die '1' und '0' Unterscheidung. Nur dachte ich, dass ich mit dem Table.Join mit einer Tabelle, die nur '1' hat, schnell die Vergleichstabelle geteilt bekomme, weil dabei ja dann alle Zeilen, in denen die Spalte keine '1' hat, ausgefiltert werden. Das heißt, es geht ja nicht darum, die Unterschiede zu markieren, sondern anschließend zu identifizieren.
... aber vielleicht ist hier das Gruppieren auch hilfreich --- 'Denk'  16
... und trotzdem verbleibt die Frage, warum der Table.Join mit der '1'-Tabelle hier nicht die gewünschte Selektion erzeugt, sondern ne Kreuztabelle erzeugt (der vorherige Table.Join, der alte und neue anhand Dateinamen vereint, macht ja genau, was ich erwarte... - nur dieser hier nicht. Das würde ich gerne verstehen)

Gruß und Dank,
RaiSta
Antworten Top
#5
Zitat:... und trotzdem verbleibt die Frage, warum der Table.Join mit der ...


Um diese Frage beantworten zu können, müsstest du in der Lage sein, hier etwas hochzuladen, mit dem das monierte Verhalten reproduziert werden kann.

Ansonsten kann ich nur festenstellen, dass ich auch schon Vergleiche gemacht habe, um neu/geändert/gelöscht ermitteln zu können und hatte damit eigentlich nie Probleme.
Antworten Top
#6
Shocked 
(30.08.2022, 14:36)ws-53 schrieb: Um diese Frage beantworten zu können, müsstest du in der Lage sein, hier etwas hochzuladen, mit dem das monierte Verhalten reproduziert werden kann.

Ansonsten kann ich nur festenstellen, dass ich auch schon Vergleiche gemacht habe, um neu/geändert/gelöscht ermitteln zu können und hatte damit eigentlich nie Probleme.

Mal sehen, wie ich ein Beispiel erstellen kann, das aussagekräftig ist. Da mein PQ-Script auf ein Firmen-Netzwerk zugreift, kann ich natürlich das Original nicht hochladen - mal sehen, ob ich was 'gebastelt' kriege, das die Problematik nachvollziehbar macht...

Ich hatte gehofft, dass ich irgendwas in der Syntax falsch gemacht habe und mich jemand auf den syntaktischen (Denk-)Fehler hinweisen kann...

Gruß und Dank,
RaiSta
Antworten Top
#7
Zitat:bevor es PQ gab, ...

Bevor es Autos gab, ist der Mensch noch mehr gelaufen, und konnte im Alter auf einen Rollator verzichten.

Ich habe es bei SAP, als Entwickler und Anwender, tatsächlich oft genug erlebt, dass mann sich in Walldorf oder sonstwo neue Anwendertools ausgedacht hatte, diese aber tatsächlich schlechter (Zumindest im Handling für den Anwender) als die alten Werkzuege waren.

Egal warum, aber bei Microsoft kann ich feststellen, dass ich einen Großteil der vielen neuen Funktionen als Verbesserung sehe.

Und wer dem "alten" nachtrauert, der muss sich ja beim Zahnarzt nur mal mit historischen (50J alt, reicht da schon) Werkzeugen behandeln lassen!
Antworten Top
#8
Warum keine getrennten Ordner?

1) Ordner 'Sammlung' - da liegen alle bereits verarbeiteten Dateien drin
2) Order 'Neu' - da kommen die neuen Dateien rein, die noch nicht bearbeitet wurden

Die 'neuen' Dateien werden nach Bearbeitung in den ordner 'Sammlung' verschoben
Gruss Ralf
Antworten Top
#9
Hallöchen,

müsstest Du beim join nicht den einen oder anderen Vergleich vornehmen?
Im Prinzip table1.column1 = table2.column99
.      \\\|///      Hoffe, geholfen zu haben.
       ( ô ô )      Grüße, André aus G in T  
  ooO-(_)-Ooo    (Excel 97-2019+365)
Antworten Top
#10
(30.08.2022, 19:21)scorefun schrieb: Warum keine getrennten Ordner?

1) Ordner 'Sammlung' - da liegen alle bereits verarbeiteten Dateien drin
2) Order 'Neu' - da kommen die neuen Dateien rein, die noch nicht bearbeitet wurden

Die 'neuen' Dateien werden nach Bearbeitung in den ordner 'Sammlung' verschoben

Ne, es geht ja nicht darum, die Tabellen zu vergleichen - das macht die 'Vergleich'-Spalte schon. Es geht jetzt nur noch darum, die Vergleich-Spalte auszuwerten. Das gelingt mir ja schon mit der in meinem Script als 'klassische' Variante gekennzeichneten Schritt. Den wollte ich aber, besonders auch angesichts der Menge an zu vergleichenden Dateien, effizienter mittels des Table.Join erreichen. Das muss auch prinzipiell funktionieren, nur irgendwas ist falsch an meinem Konstrukt. Diesen Fehler suche ich, damit das Kreuzprodukt zur Auslese wird - eigentlich finde ich das mit dem Table.Join eleganter als die 'klassische' Variante, da damit auf ganz elementare Funktionen einer Datenbank zurückgegriffen wird.
Alle anderen Vorschläge, was ich am Gesamtkonstukt ändern könnte, sind prinzipiell interessant, gehen aber im Detail an der gestellten Frage vorbei.

Gruß und Dank,
RaiSta

(30.08.2022, 19:31)schauan schrieb: müsstest Du beim join nicht den einen oder anderen Vergleich vornehmen?
Im Prinzip table1.column1 = table2.column99

Der Vergleich ist intrinsisch in der Syntax des Table.Join-Befehls enthalten, muss nicht mehr explizit angegeben werden.

Gruß und Dank,
RaiSta
Antworten Top


Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste