ole-objekt
Goto Top

Invoke-sqlcmd und Zellen mit null-Wert

Hallo!
Ich verzweifle seit 2 Tagen an invoke-sqlcmd, habe gefühlt schon das gesamte internet leer gelesen und kann mir nicht vorstellen, dass ich der erste mit diesem Problem bin und das noch niemand gelöst hat:

invoke sqlcmd liefert keine Null-Werte, d.h. wenn das Feld in der Datenbank null enthielt, habe ich jetzt eine leere Zelle in der Ergebnis-Tabelle (genau gesagt in der row-collection). Ich muss aber in der letztlich zu erstellenden Date null haben, weil die Datei in ein System hochgeladen werden soll, das leere Zellen nicht akzeptiert.

Mein bisheriger Code:

$dbResult = Invoke-Sqlcmd -Query $Sql -ConnectionString $global:ConStr -OutputAs DataTables
$dbResult | forEach-Object {
     foreach ($dbColumn in $dbResult.Columns) { 
          if  ($_.Item($dbColumn).ToString().Length -eq 0) { 
               'null'   
          } else { $_.Item($dbColumn) }
     }
} | Export-CSV -path $sTempFile -NoTypeInformation -Encoding $oWork.Encoding -UseCulture -UseQuotes Never

Ich versuche also, die einzelnen Zeilen (und darin die einzelnen Spalten) durchzugehen, die leeren Zellen zu erkennen und ggf 'null' zu setzen. Beim Debuggen des Codes sehe ich auch, dass die Erkennung funktioniert. Aber
1. erscheint in der entstehenden Datei keine null
2. ist die entstehende Datei total falsch. Statt 40 Spalten mit 16000 Zeilen gibt es eine Spalte mit 700000 Zeilen (alles ca.). Ohne den Versuch, durch die Zeilen und Spalten zu gehen, entsteht eine Datei im korrekten Format.

Ich würde mich freuen, wenn mir jemand
a) sagen würde, wo mein Code falsch ist oder
b) einen ganz anderen Ansatz liefern könnte.

Herzlichen Dank schonmal im Voraus,
Olaf

Content-ID: 63708510548

Url: https://administrator.de/contentid/63708510548

Ausgedruckt am: 23.11.2024 um 01:11 Uhr

12168552861
Lösung 12168552861 13.04.2024, aktualisiert am 14.04.2024 um 07:32:27 Uhr
Goto Top
Teste mal (habe gerade kein Zugriff auf Invoke-SQLCmd
$dbResult = Invoke-Sqlcmd -Query $Sql -ConnectionString $global:ConStr -OutputAs DataTables
$result = foreach($entry in $dbResult.Rows){
     $new = [ordered]@{}
     foreach($dbColumn in $dbResult.Columns){
         $new.$dbcolumn = $entry[$dbColumn]
         if ($entry[$dbColumn] -in @([system.dbnull]::Value,$null,'')){  
            $new.$dbcolumn = 'null'  
         }
     }
     [pscustomobject]$new
}
If($result){
    $result | Export-CSV -path $sTempFile -NoTypeInformation -Encoding $oWork.Encoding -UseCulture -UseQuotes Never
}
https://tio.run/##fZAxb8IwEIX3/AoPkexIJgsbElJQKzY6tBVLlMGJD5HWsZHtNEWI35 ...

Gruß
ole-objekt
ole-objekt 14.04.2024, aktualisiert am 18.04.2024 um 13:14:14 Uhr
Goto Top
<edit: Nach Überarbeitung der Antwort von meisterroehrich ist dieser Kommentar eigentlich hinfällig, ich lösche ihn wegen des brute-force-Ansatzes dann trotzdem nicht.>

Hallo Meister Röhrich,

funktioniert eigentlich, allerdings bekomme ich einen Fehler bei numerischen Spalten, dass 'null' nicht erlaubt sei. Im Ergebnisset kann ich auch den DataType nicht mehr zu char ändern, die Fehlermeldung heißt "Cannot change DataType of a column once it has data." Klingt ja irgendwie auch verständlich...

Ein anderer Ansatz war, das Ergebnis nicht in die endgültige Datei zu schreiben, sondern erstmal in eine temporäre. In dieser kann dann mittels
Get-Content -Encoding $oWork.Encoding $sTempFile | foreach-object {$_.replace('""','null').Replace(',,',',null,').Replace(';;',';null;').Replace('-1',';null;').Replace(';,000',';null;')} | Out-File -FilePath $sExportFile -Encoding $oWork.Encoding   
das null nachträglich eingefügt werden. Bei mehreren aufeinander folgenden leeren Spalten wird allerdings nur jede zweite gefunden. D.h. ich habe das ganze jetzt mit einem brute force Ansatz gelöst:
Das Kopieren und ersetzen erfolgt zwei Mal hintereinander (!) wie oben beschrieben (von sTempFile zu sTempFile1, dann von sTempFile1 zu sTempFile2). Dann erfolgt es noch ein drittes Mal mit
Get-Content -Encoding $oWork.Encoding $sTempFile2 | foreach-object {$_ -replace ';$',';null'} | Out-File -FilePath $sExportFile -Encoding $oWork.Encoding   
um die letzte Spalte auch noch zu erwischen. Das ist zwar nicht schön, funktioniert aber. Falls noch jemandem eine elegantere Variante einfällt, freue ich mich auf weitere Ideen.

Herzlichen Dank für den Input und schöne Grüße an Frau Hansen!
Olaf
12168552861
Lösung 12168552861 14.04.2024 aktualisiert um 07:43:35 Uhr
Goto Top
Moin.
Nee lass das mit dem Replace das ist Humbug. Habe es oben entsprechend angepasst, sollte jetzt kein Problem mehr darstellen.

schöne Grüße an Frau Hansen!
Likörchen geht immer, näch 😂.
wiesi200
wiesi200 14.04.2024 um 17:34:30 Uhr
Goto Top
Hallo,

und wenn du innerhalb deiner SQL Query das Problem schon angehst? Dafür gibt's "ISNULL"
em-pie
em-pie 14.04.2024 um 22:45:55 Uhr
Goto Top
Moin,

Ich muss aber in der letztlich zu erstellenden Date null haben, weil die Datei in ein System hochgeladen werden soll, das leere Zellen nicht akzeptiert.
Kannst du doch mittels des Ansatzes des Kollegen @wiesi200 Kompensieren:
Numerische und nicht numerische Felder fängst du im Query mit folgendem ab:
Select 
  ISNULL(table.myInteger, 0) as myInteger
  , ISNULL(table.myString, '') as myString   
FROM table
Legt Join anotherTable on blablabla

Dann erhältst du kein NULL (was bei einem CSV-Export sogar Mist wäre) sondern eine 0 bzw. ein Feld mit einem leeren Inhalt (was != Null ist).

Wir haben auch solch ein System und kompensieren das damit. Macht das Query zwar „länger“, aber das ist Wurscht. Sieht ja keiner aus uns Admins/ DBAs face-smile
ole-objekt
ole-objekt 18.04.2024 um 13:11:15 Uhr
Goto Top
Der angepasste Code von meisterroehrich löst mein Problem und ist zu allem Überfluss auch schön schnell. Herzlichen Dank dafür!

Die Vorschläge von wiesi200 und em-pie helfen mir leider nicht weiter.
1. Bei einer Integer-Spalte kann ich im isnull nicht den Wert 'null' setzen, weil der ja kein Integer ist.
2. Statt 'null' eine 0 zu schreiben, wäre bei Bool-Spalten eine Veränderung der Bedeutung von "unbekannt" zu "nein"
wiesi200
wiesi200 18.04.2024 um 13:22:35 Uhr
Goto Top
em-pie
em-pie 18.04.2024 um 13:30:56 Uhr
Goto Top
Moin,

1. Bei einer Integer-Spalte kann ich im isnull nicht den Wert 'null' setzen, weil der ja kein Integer ist.
Du sollst ja auch 0 und nicht NULL einsetzen! Schaue bitte, was ISNULL() macht

2. Statt 'null' eine 0 zu schreiben, wäre bei Bool-Spalten eine Veränderung der Bedeutung von "unbekannt" zu "nein"
Bei Spalten mit Bool nimmt man ja dann auch True/ False
https://www.sqlshack.com/sql-boolean-tutorial/
ole-objekt
ole-objekt 20.04.2024 um 01:39:26 Uhr
Goto Top
Meine Anforderung ist aber, bei einem null-Wert in der Datenbank dann den Wert "null" in der entstehenden csv-Datei zu haben. Ursprünglich wurde dann ein leeres Feld exportiert. Und wenn ich statt null 0 setze, ändere ich die Bedeutung.
Und ja, eigentlich würde man bei Bool true/false setzen. Wir haben hier aber "aus historischen Gründen" tinyint-Spalten, in denen dann nur 0 oder 1 vorkommen darf - und null.
Aber die Sache ist ja nun dank meisterroehrich gelöst. Hier sind keine weiteren Antworten mehr nötig
wiesi200
wiesi200 20.04.2024 um 04:27:44 Uhr
Goto Top
Ich persönlich hätte dann DB seitig vielleicht sogar 0,1,2 gearbeitet und keinen Nullwert zugelassen.

0 = unbekannt
1 = ja
2 = nein

Aber eher Geschmackssache und stark Situations und Tageslaunenabhängig