springstil
Goto Top

CSV Import zu SQL Server mit Powershell

Hallo zusammen,

ich bin gerade etwas am verzweifeln und hoffe mir kann jemand hierbei helfen...

Ich würde gerne mit Hilfe von Powershell CSV Dateien in eine SQL Datenbank einspielen.

Es geht dabei um 4 CSV Dateien die in 4 Verschiedene Tabellen importiert werden müssen. Alle ";" getrennt.

Mein Export aus der ersten Instanz funktioniert super, habe ich auch gut hinbekommen, nur verzweifle ich am Letzten teil und zwar dem Import.. Ich hab auch schon einige Seiten durch gegoogelt, finde aber meistens nur etwas wo eine NEUE Datenbank erstellt wird und importiert wird. Ich möchte die Daten aber in eine Bestehende importieren.

Content-ID: 1888271262

Url: https://administrator.de/forum/csv-import-zu-sql-server-mit-powershell-1888271262.html

Ausgedruckt am: 22.12.2024 um 11:12 Uhr

Coreknabe
Coreknabe 11.02.2022 um 10:27:30 Uhr
Goto Top
Springstil
Springstil 11.02.2022 um 10:57:20 Uhr
Goto Top

Ja das hab ich auch schon gefunden, habe nur die ganze zeit nicht verstanden wieso er eine Temp Tabelle anlegt... Allerdings scheint es mir als wenn mein Chrome / Addons nicht wollte das ich alles lesen kann... Ich hab mir nun mal den unteren Abschnitt durchgelesen und mir den Code genauer angeschaut und nun verstanden wieso weshalb warum das so gemacht wird face-smile Ich probier das mal aus Danke
mbehrens
mbehrens 11.02.2022 um 11:08:12 Uhr
Goto Top
Zitat von @Springstil:

ich bin gerade etwas am verzweifeln und hoffe mir kann jemand hierbei helfen...

Ich würde gerne mit Hilfe von Powershell CSV Dateien in eine SQL Datenbank einspielen.

Die passenden .NET/ODBC Bindings für Firebird sind installiert?
colinardo
colinardo 11.02.2022 um 11:18:22 Uhr
Goto Top
Servus.
Da muss man sich heute keinen mehr abwürgen
Write-SqlTableData

Grüße Uwe
Springstil
Springstil 11.02.2022 um 15:03:19 Uhr
Goto Top

Ich hab mir das Skript jetzt was umgeschrieben das es in der Theorie Läuft. Problem ist jetzt allerdings nur das wenn ich IDENTITY_INSERT auf ON setze er meine Laufendenummer nicht übernimmt... und ohne das auf ON zu setzen kann ich nicht importieren.


Zitat von @colinardo:

Servus.
Da muss man sich heute keinen mehr abwürgen
Write-SqlTableData

Grüße Uwe

Habe ich versucht, scheiter allerdings an der Fehlermeldung :

Der angegebene Wert vom Typ String aus der Datenquelle kann nicht in Typ int der angegebenen Zielspalte konvertiert werden.

und weiß nicht wie ich das hinbekomme.
colinardo
Lösung colinardo 11.02.2022 aktualisiert um 17:29:56 Uhr
Goto Top
Zitat von @Springstil:
Habe ich versucht, scheiter allerdings an der Fehlermeldung :

Der angegebene Wert vom Typ String aus der Datenquelle kann nicht in Typ int der angegebenen Zielspalte konvertiert werden.

und weiß nicht wie ich das hinbekomme.
Da stimmt der Datentyp eben nicht ... Mit dem SQL-CMDLet
$server = 'server.domain.tld'  
$database = 'mydb'  
$table = 'MyTable'  
$username = 'USER'  
$password = 'Password'  

$creds = (new-Object PSCredential($username,(ConvertTo-SecureString $password -AsPlainText -Force)))

$dt = Read-SqlTableData -ServerInstance $server -DatabaseName $database -TableName $table -OutputAs DataTable -TopN 1 -Credential $creds
$dt.Rows.Clear()
$csv = Import-CSV "C:\test.csv" -Delimiter ";"  

$cols =  $csv | gm -MemberType NoteProperty | select -Expand Name
# fill datatable
foreach($row in $csv){
    # create datarow 
    $dr = $dt.NewRow()
    # fill row with data from columns
    $cols | %{$dr[$_] = $row.$_}
    # add row
    $dt.Rows.Add($dr)
}
$dt | Write-SqlTableData -ServerInstance $server -DatabaseName $database -TableName $table -Credential $creds

Oder eben auf dem manuellen Weg ohne das SQL-Module mit reinen .NET Objekten
<#
    SQL - Insert CSV Files into Database via Datatable
#>

# Folder with csv data files
$folder = 'D:\csv_files'  
# File extension
$extension = '*.csv'  
# Database Servername
$server = 'myserver.domain.tld'  
# Databasename
$database = 'MyDataBase'  
# Tablename
$table = 'demotable'  
# Credentials
$username = 'dbsqluser'  
$password = 'Passw0rd'  

try{
    # connection object
    $conn = new-object System.Data.SqlClient.SqlConnection
    # connection string
    $conn.ConnectionString = “Server=$server;Database=$database;Integrated Security=False;UID=$username;PWD=$password# open connection
    $conn.Open()
    # create data adapter
    $adapter = New-Object System.Data.SqlClient.SqlDataAdapter("SELECT TOP 1 * FROM $table",$conn)  
    # create datatable to hold insert batches
    $dt = New-Object System.Data.DataTable
    # update schema of datatable to match the table in the database
    $adapter.FillSchema($dt,[System.Data.SchemaType]::Source)
    # auto create insert/update commands
    $cmdbuilder = New-Object System.Data.SqlClient.SqlCommandBuilder($adapter)
    # enumerate all files
    foreach($file in (Get-ChildItem $folder -Filter $extension -File)){
        # import csv data
        $csv = Import-CSV $file.Fullname -Delimiter ";"  
        # extract column names
        $cols =  $csv | gm -MemberType NoteProperty | select -Expand Name
        # fill datatable
        foreach($row in $csv){
            # create datarow 
            $dr = $dt.NewRow()
            # fill row with data from columns
            $cols | %{$dr[$_] = $row.$_}
            # add row
            $dt.Rows.Add($dr)
        }
        # execute update
        $cnt = $adapter.Update($dt)
        write-host "Inserted $cnt number of rows from '$($file.FullName)' into '$table' in '$database'." -F Green  
        [void]$dt.Rows.Clear()
    }
}catch{
    # error occured
    Write-host $_.Exception.Message -F Red
}finally{
    # cleanup
    $adapter.Dispose()
    $dt.Dispose()
    $cmdbuilder.Dispose()
    $conn.Close()
}

It's your choice ...
Springstil
Springstil 14.02.2022 aktualisiert um 09:06:04 Uhr
Goto Top
Zitat von @colinardo:

Zitat von @Springstil:
Habe ich versucht, scheiter allerdings an der Fehlermeldung :

Der angegebene Wert vom Typ String aus der Datenquelle kann nicht in Typ int der angegebenen Zielspalte konvertiert werden.

und weiß nicht wie ich das hinbekomme.
Da stimmt der Datentyp eben nicht ... Mit dem SQL-CMDLet
$server = 'server.domain.tld'  
$database = 'mydb'  
$table = 'MyTable'  
$username = 'USER'  
$password = 'Password'  

$creds = (new-Object PSCredential($username,(ConvertTo-SecureString $password -AsPlainText -Force)))

$dt = Read-SqlTableData -ServerInstance $server -DatabaseName $database -TableName $table -OutputAs DataTable -TopN 1 -Credential $creds
$dt.Rows.Clear()
$csv = Import-CSV "C:\test.csv" -Delimiter ";"  

$cols =  $csv | gm -MemberType NoteProperty | select -Expand Name
# fill datatable
foreach($row in $csv){
    # create datarow 
    $dr = $dt.NewRow()
    # fill row with data from columns
    $cols | %{$dr[$_] = $row.$_}
    # add row
    $dt.Rows.Add($dr)
}
$dt | Write-SqlTableData -ServerInstance $server -DatabaseName $database -TableName $table -Credential $creds


Wie immer vielen dank für deine hilfe, ich bekomme den Fehler:
Es ist nicht möglich, eine Methode für einen Ausdruck aufzurufen, der den NULL hat.
In Zeile:21 Zeichen:5
+     $dt.Rows.Add($dr)
+     ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) , RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

Ich verstehe nur nicht warum er sagt "NULL" alle Felder sind befüllt

Mit dem Anderen Code funktioniert es, mich würde es allerdings für den Lerneffekt interessieren wieso er beim anderen NULL anmeckert
colinardo
colinardo 14.02.2022 aktualisiert um 09:18:18 Uhr
Goto Top
Ich verstehe nur nicht warum er sagt "NULL" alle Felder sind befüllt
Da hat deine Tabelle wohl keinen Inhalt, denn der erste Eintrag davon wird in Zeile 9 abgefragt. Der ist indem Fall $null. Die Prüfung auf $null hatte ich auf die schnelle weg gelassen.
Die Variante geht davon aus das schon Inhalt in der Tabelle vorhanden ist, um sich das Typenschema mit der DataTable zu holen.
Lässt sich natürlich auch wie beim zweiten Code via DataAdapter anpassen wenn man will, oder man erstellt die DataTable und die Columns manuell, wichtig ist das man eine DataTable bekommt in der das Spaltenschema inkl Datentyp enthalten ist bekommt, der Inhalt ist egal der wird eh aus der Datatable entfernt, bevor man sie neu mit Spalten füllt.
Springstil
Springstil 14.02.2022 um 16:05:14 Uhr
Goto Top
Stimmt.. die Original Datenbank Tabelle war zu dem Zeitpunkt leer da ich die nur zum testen genommen habe. Aber es klappt ja jetzt soweit face-smile danke