Power Query - CSV einlesen ohne Quote-Zeichen
#21
Hi,

das ist doch mal eine Antwort, wie ich sie mir wünsche! Denn in Bezug auf PQ würde ich mich immer noch als Anfänger bezeichnen. Und als Autodidakt helfen einem solche Postings wesentlich mehr als ein "der Fehler ist doch offensichtlich".

Ich wäre nie auf die Idee gekommen, dass PQ sich beim Trennen nach Trennzeichen nur an der ersten Zeile orientiert. Insbesondere weil es beim Öffnen als Csv-Datei ja auch die richtigen Spaltenzahl ermittelt. Solche Problematiken sind mir als Anfänger in PQ halt nicht geläufig.

Und dass meine Datei keine "echte" Csv-Datei ist, ist mir auch klar. Aber aus SAP bekomme ich halt nichts besseres raus. Das mag auch daran liegen, dass ich mit SAP eigentlich nicht viel am Hut habe. Wahrscheinlich bin auch hier einfach zu unfähig.

Zum Thema Spalten löschen: da gibt es so viele Möglichkeiten, dass ich trotz googeln einfach nicht erraten kann, welche Methode du meinst. Die, die ich verwende, funktioniert hervorragend.



Dann hätte ich noch ein paar Fragen an @Luschi:

Welchen Sinn macht die Zeile
Code:
nix = null,
Verwendest du das um später bei Bedarf "nix" statt "null" tippen zu können? Oder dient das nur zu meiner Verwirrung? 19

Hat es einen tieferen Sinn, dass du
Code:
#"Entfernte oberste Zeilen" =  Table.Skip(Quelle, each Text.Start(Text.Trim(Text.Clean([Column1])), 4) <> "Banf"),
statt des einfacheren
Code:
#"Entfernte oberste Zeilen2" = Table.Skip(Quelle,4),
verwendest ?
Klar hier müssen es immer genau 4 Zeilen sein und bei deiner Variante können es beliebig viele werden. Aber solange es immer 4 Zeilen sind, sollte doch die einfache Variante genügen, oder? Trotzdem werde ich mir das merken, denn in anderen Dateien habe ich genau dieses Problem.

Du verwendest
Code:
#"Ersetzter Wert" = Table.ReplaceValue(#"Gefilterte Zeilen1","00.00.0000","",Replacer.ReplaceText,
        Table.ColumnNames(#"Gefilterte Zeilen1")),
anstatt die Spalten einzeln aufzuführen. Das finde ich genial. Hättest du auch einen ähnlichen Trick für den nächsten Schritt, nämlich der Zuweisung des richtigen Datentyps für alle Spalten? Die Automatik von PQ funktioniert hier nicht, da ich die meisten Spalten als Text brauche, auch wenn sie wie Zahlen aussehen. Am liebsten hätte ich einen Schritt der sagt: Mach mal alle Spalten zu Text. Dann würde ich im nächsten Schritt bei den paar Ausnahmen als Format Datum bzw. Zahl setzen.



Noch eine Anmerkung: Meine Probleme kommen ganz offensichtlich aus der Tatsache, dass SAP für den Kurztext ein freies Textfeld bietet, in das man alles eintragen darf. Eben auch ein einzelnes Anführungszeichen. Mittlerweile habe ich den Verdacht, dass auch die wechselnde Spaltenzahl damit zusammenhängt (falls jemand ein Tab-Zeichen ins Feld kopiert). Muss ich nachher mal ausprobieren. Wenn dem so ist, dann werde ich diese Spalte einfach bei der Ausgabe ans Ende der Liste nehmen und kann dann sogar wieder den normeln Csv-Import verwenden.
Gruß,
Helmut

Win10 - Office365 / MacOS - Office365
Antworten Top
#22
Hallo Helmut,

- nix = null, //verhintdert die PQ-Schritt-Umbenennung in 'Navigation', das hasse ich
- sollten mehr oder weniger als 4 Zeilen von oben geköpft werden müssen
  dann ist meine Variante die bessere Wahl
- sind es garantiert immer 4 Zeilen, die weg müssen, dann Deine Variante
  aber da muß man sich dann auch 100%ig sicher sein und wer ist das schon
  trotzdem sieht meine Variante professioneller aus - und das ist wichtig, um beim AG zu punkten 
- wenn man 10 Spalten hat, ist das Aufzählen der Spaltennamen kein Problem
  aber ich versuche oft, mit M-Mitteln dies allgemeiner zu schreiben
- für die Spaltentyp-Definition benutze ich eine Hilfstabelle
  ich mache Dir heute Abend dafür mal 1 Beispiel dafür.

Gruß von Luschi
aus klein-Paris
[-] Folgende(r) 1 Nutzer sagt Danke an Luschi für diesen Beitrag:
  • HKindler
Antworten Top
#23
Experimentierfreudig scheinst Du ja nicht zu sein und dann kommt da so ein Simpel wie Warkings um die Ecke und beschwert sich.

Übrigens, es geht natürlich auch
Code:
= Csv.Document(File.Contents("D:\Tmp\ZMM_PR_REL.txt"),[Encoding=1252, QuoteStyle=QuoteStyle.None])

Microsoft weiß auch: CSV ist nicht immer CSV und alle sagen CSV  16

Und das Löschen leerer Zeilen mach ich Simpel auch simpel, also vom Ansatz her, ist aber bei größeren Datenmengen ein Performance Killer. Bei 20 bis 30 TSD Datensätzen ist das IMHO aber egal.

Transponieren, Löschen, Transponieren, aber das ist wahrscheinlich auch zu vage. 

So muss ich nichts über den Inhalt oder die Spaltenüberschriften annehmen, so wie Du. Wenn der Programmierer des offensichtlich kundeneigenen Programms ZMM_PR_REL auf die Idee kommt, alle Spaltennamen mit einem Unterstrich zu beginnen, geht Dein Ansatz fliegen.
[-] Folgende(r) 1 Nutzer sagt Danke an Warkings für diesen Beitrag:
  • HKindler
Antworten Top
#24
Hi Luschi,

vielen Dank für deine Antworten.
  • Das mit "Navigation" gefällt mir auch nicht. Aber da ich idR. nicht händisch anfange, sondern von PQ das Grundgerüst erstellen lasse, ist es meist schon zu spät. Trotzdem: nice to know.
  • Es sind hier garantiert immer 4 Zeilen, da bin ich mir sicher.
  • Ich muss meinem AG nichts beweisen. So tief schaut keiner hinter die Kulissen.
  • Das mit dem Beispiel wäre super, da ich oft viele Spalten habe (die gut 50 hier sind noch relative wenig, das können auch mal 100 und mehr sein). Daher wäre so etwas wie "alle Spalten sind Text" wirklich hilfreich.

Übrigens habe ich das mit dem Verschieben des Kurztextes ans Ende der Spalten getestet. Dann könnte man es tatsächlich wieder als CSV-Datei lesen. Hätte allerdings am Ende einige leere Spalten, sobald #(tab)-Zeichen in der Kurzbeschreibung auftauchen. Daher benutze ich jetzt weiter den Textimport, lösche die oberen Zeilen und lasse anhand der dann ersten Zeile (den Überschriften) die Spalten trennen. Dabei werden die Kurzbeschreibungen am ersten #(tab) abgeschnitten. Damit kann ich leben, da dies nur wenige Positionen betrifft. Und falls sich jemand darüber beschwert, soll er dem auf die Finger klopfen, der die #(tab) eingefügt hat.

Jetzt oute ich mich mal wieder als PQ-Anfänger: Ich habe raus gefunden, dass man sich das alles auch mit der Maus zusammenklicken kann.
Einfach beim Anlegen der Abfrage als Text/CSV-Datei nach dem wählen der Datei unten links auf "Tabelle anhand von Beispielen extrahieren" auswählen.
Dann in der unteren Hälfte des folgenden Fensters unterhalb von Spalte "1" den Anfang der Kopfzeile eintippen (in meinem Fall "Banf") und dann den untersten Eintrag (die komplette Zeile) der aufpoppenden Liste auswählen.
Unterhalb der Zeilen auf das "+" tippen, den Angang der ersten Nummer eintippen und wieder die komplette Zeile auswählen. Erneut auf das "+" tippen. Staunen und auf "OK" klicken.
Jetzt ist man genau so weit, dass man nur noch im normalen PQ auf "Spalte teilen" --> "Nach Trennzeichen" klicken muss.
Bei "Anführungszeichen" "Keine" auswählen, "OK"
"Erste Zeile als Überschriften verwenden"
Fertig! Nun ja, fast, es gibt ev. noch ein paar Spalten zu viel, ein paar Leerzeichen bei den Spaltenüberschriften zu viel und andere Kleinigkeiten wie falsche Spaltentypen, aber im Grunde ist man fertig.

Trotzdem ist da dann natürlich einiges nicht so elegant gelöst wie im jetzigen Fall, aber ich bin echt erstaunt, dass man im Grunde mit einfachen Mausklicks soweit kommt.
Gruß,
Helmut

Win10 - Office365 / MacOS - Office365
Antworten Top
#25
Zitat:...  aber ich bin echt erstaunt, dass man im Grunde mit einfachen Mausklicks soweit kommt.

Dann sollte dir auch spätestens jetzt klar sein, dass kein nur halbwegs vernünftiger IT-ler jemals auf die Idee käme, aus einer erklickbaren Lösung anschließend eine 1-Schrittabfrage zu erstellen, bei der nicht mehr schrittweise getestet und die auch nur mit viel Aufwand gewartet werden kann.

Natürlich wirst du mit der Zeit feststellen, dass du auch Funktionen benötigst, die sich nicht erklicken lassen.
Antworten Top
#26
Hi Warkings,

in gewisser Weise bin ich durchaus experimentierfreudig, wie du an meinem obigen Post sehen kannst. Nur fehlen mir halt oft die Ansätze - vermutlich mangels Fantasie.

Transponieren - Löschen - Transponieren, darauf muss man erst mal kommen (und nein, das ist nicht zu vage ausgedrückt, ich wusste sofort, was gemeint ist). Da denke ich von Excel und VBA her zu sehr in Einzelschritten und nicht in Datenbanken. Beim Googeln bin ich auch nicht darauf gestoßen. Wahrscheinlich fehlte mir auch hier einfach das richtige Stichwort.

Danke für den Hinweis!

Die Transaktion ZMM_PR_REL ist vermutlich (so genau weiß ich das nicht) eine einfache Datenbankabfrage. Zumindest konnte auf meinen Wunsch hin innerhalb von wenigen Minuten eine weitere Spalte mit ausgegeben werden, die bis dato gefehlt hat. Und wenn hier irgendjemand die Spaltennamen ändert, dann habe ich mit meiner Abfrage so oder so ein Problem, da dann allein schon die Festlegung des Spaltentyps zu einem Fehler führt.

Aber durch meinen jetzigen Ansatz (die Spalte "Kurztext" von SAP als letztes ausgeben lassen, als Textdatei einlesen, erste Zeilen löschen, Spalten trennen anhand der #(tab) in der künftigen Überschriftenzeile) muss ich nur noch die erste Spalte löschen. Problem behoben.
Gruß,
Helmut

Win10 - Office365 / MacOS - Office365
Antworten Top
#27
Hallo PQ-Fan's

die Schrittfolge 'Transponieren - Löschen - Transponieren' ist bei wenigen Duzend DS und nicht vielen Spalten  ein probates Mittel:
- aber bei mehr als tausende DS + 100+ Spalten ist das ein totales Ausschlußkriterium

Gruß von Luschi
aus klein-Paris
Antworten Top
#28
Ich hab es mit 80K Records und den Spalten aus obigen Beispiel probiert, der Vorgang hat ca. 15s gedauert, also erträglich.

Wie ich geschrieben habe
Zitat:... ist aber bei größeren Datenmengen ein Performance Killer. ...
daher würde ich der Aussage 
Zitat:- aber bei mehr als tausende DS + 100+ Spalten ist das ein totales Ausschlußkriterium
zum Teil widersprechen. Es geht schon was, nur mit mäßiger Performance eben.  
Aber stimmt schon, man sollte wissen, was man tut.

PS Mal einen (nicht repräsentativen) Test gemacht. 
120K mit 36 Spalten ~ 20s
240K  mit 36 Spalten ~ 50s
Das würde ich akzeptieren. Ich lade die Daten ja höchstens einmal am Tag
   

PPS Auch einen (nicht repräsentativen) Test mit ~ 200 Spalten und 5K Datensäten gemacht. 
Daten werden innerhalb von 5s geladen
200 Spalten und 60K war auch nicht so schlecht, aber schon 90s

Na ja, alles Experten hier  19
Antworten Top
#29
Hi ws-53
(01.08.2024, 14:39)ws-53 schrieb: Dann sollte dir auch spätestens jetzt klar sein, dass kein nur halbwegs vernünftiger IT-ler jemals auf die Idee käme, aus einer erklickbaren Lösung anschließend eine 1-Schrittabfrage zu erstellen, bei der nicht mehr schrittweise getestet und die auch nur mit viel Aufwand gewartet werden kann.
Habe ich jemals etwas anderes behauptet? Nachvollziehbarkeit und Wartbarkeit hat bei mir eine sehr hohe Priorität. Wobei auch die Übersichtlichkeit nicht vernachlässigt werden darf.

Mein Code sieht nun so aus:
Code:
let
    Quelle = Table.FromColumns({Lines.FromBinary(File.Contents(RootPath & SubPath & "ZMM_PR_REL.txt"), null, null, 1252)}),
    #"Entfernte oberste Zeilen" = Table.Skip(Quelle,4),
    #"Spalte nach Trennzeichen teilen" = Table.SplitColumn(#"Entfernte oberste Zeilen", "Column1", Splitter.SplitTextByDelimiter("#(tab)", QuoteStyle.None)),
    #"Entfernte Spalten" = Table.RemoveColumns(#"Spalte nach Trennzeichen teilen",{"Column1.1"}),
    #"Höher gestufte Header1" = Table.PromoteHeaders(#"Entfernte Spalten", [PromoteAllScalars=true]),
    #"Spaltennamen trimmen" = Table.TransformColumnNames(#"Höher gestufte Header1", Text.Trim),
    #"Gefilterte Zeilen1" = Table.SelectRows(#"Spaltennamen trimmen", each [Banf] <> null and [Banf] <> ""),
    #"Ersetzter Wert" = Table.ReplaceValue(#"Gefilterte Zeilen1","00.00.0000","",Replacer.ReplaceValue,{"BestDatum"}),
    #"Geänderter Typ" = Table.TransformColumnTypes(#"Ersetzter Wert",{{"Banf", type text}, {"Pos.", type text}, {"AnfDatum", type date}, {"Angel.von", type text}, {"BArt", type text}, {"Frg", type text}, {"Material", type text}, {"Kurztext", type text}, {"Anforderungsmenge", type number}, {"ME", type text}, {"Bewertpreis", type number}, {"Währg", type text}, {"pro", Int64.Type}, {"ME_1", type text}, {"Gesamtwert bei Freigabe", type number}, {"Währg_2", type text}, {"Lfd", type text}, {"K", type text}, {"Genehmigende Kostenstelle", type text}, {"Kostenst.", type text}, {"Auftrag", type text}, {"Sachkonto", type text}, {"Infosatz", type text}, {"Werk", type text}, {"LOrt", type text}, {"BedarfsNr.", type text}, {"Warengruppe", type text}, {"EKG", type text}, {"Wunschlief", type text}, {"Fst.Lief", type text}, {"EkOr", type text}, {"Bestellung", type text}, {"Pos._3", type text}, {"BestDatum", type date}, {"Lieferdatum", type date}, {"KST", type text}, {"KST_kurz", type text}, {"Prozent", Percentage.Type}}),
in
    #"Geänderter Typ"
Hier gibt es nichts mehr, was nicht zusammenklicken kann.
Gruß,
Helmut

Win10 - Office365 / MacOS - Office365
Antworten Top
#30
Hallo Helmut,

hier mal meine Variante, die Spaltentyp-Erkennung zu beeinflussen mit den Mitteln von PQ-M.
Dazu gibt es eine interne Funktion in der Abfrage 'ZMM_PR_REL_2'. Wollte diese Funktion auslagern, aber da kommt dann die Fehlermeldung: Zyklischer Verweis.
Zur Zeit werden nach gewissen Kriterien der Spaltennamen die Datentypen festgelegt in 1 'lists in list' Liste, also Spaltenname und Datentyp, die Du natürlich weiter verfeinern kannst.
Ein paar Infos im M-Code helfen Dir joffentlich beim Beacken des M-Codes.

Gruß von Luschi
aus klein-Paris


Angehängte Dateien
.zip   BANF_1.zip (Größe: 246,96 KB / Downloads: 4)
Antworten Top


Gehe zu:


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