0

I'm using PowerShell to import a .CSV file and I need to save its contents to a database.

I'm using the code below to pull information from the .CSV file, and put it into the database

foreach($row in $data) {
    $sql = "INSERT INTO Offerings (RATING, PARVALUE, DESCRIPTION, COUPON, MATURITY, DATEDDATE, CALLDATE, FIRSTCOUPON, CUSIP, PRICEYIELD, COM) VALUES( `
    '$(($row.rating).trim())', `
    '$(($row."PAR VALUE").trim())',`
    '$(($row.DESCRIPTION).trim())', `
    '$(($row.COUPON).trim())', `
    '$(($row.MATURITY))', `
    '$(([datetime]$row."DATED DATE"))', `
    '$(($row."CALL DATE").trim())', `
    '$(($row."FIRST COUPON"))', `
    '$(($row.CUSIP).trim())', `
    '$(($row."PRICE/YIELD").trim())',`
    '$(($row.COM).trim())' `
    )"

    $command.CommandText = $sql
    $command.ExecuteNonQuery() | out-null
}

The columns $row.MATURITY/$row."CALL DATE" and $row."FIRST COUPON" are all dates (the columns in the database are of type DATE).

But the insert is passing it as a string, which the database complains that it can't convert string to DATE. How can I pass it as a date in the PowerShell command so it will write correctly to the database (as DATE type)?

Thanks!

3
  • The easiest way is to insert into a staging table whose columns are varchar data type, and then you can transform data in staging table to your designated table. Commented May 8, 2018 at 17:02
  • 3
    I dont know the format of your data. But you should be able to something like this for your $row.Maturity : '$((Get-Date $row.MATURITY -Format "yyyy-MM-dd HH:mm:ss"))', Commented May 8, 2018 at 17:06
  • You probably need to convert it to a date in SQL. That is to say the SQL command that you execute from powershell should utilize a database function like TO_DATE. Commented May 8, 2018 at 17:07

1 Answer 1

5

String concatenation is a very bad idea. It doesn't just open your code to SQL injection, it's extremely fragile.

Use a parameterized query. Assuming you're using SQL Server:

$sql = "INSERT INTO Offerings (RATING, PARVALUE, DESCRIPTION, COUPON, MATURITY, DATEDDATE, CALLDATE, FIRSTCOUPON, CUSIP, PRICEYIELD, COM) " +
    "VALUES (@RATING, @PARVALUE, @DESCRIPTION, @COUPON, @MATURITY, @DATEDDATE, @CALLDATE, @FIRSTCOUPON, @CUSIP, @PRICEYIELD, @COM)"

$command.CommandText = $sql

# Add your parameters and define their types to match the types in the Offerings table
# The System.Data.SqlDbType type includes all SQL Server data types
# For data type mapping, see https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-data-type-mappings
[void]$command.Parameters.Add('@RATING', [System.Data.SqlDbType]::NVarChar)
[void]$command.Parameters.Add('@PARVALUE', [System.Data.SqlDbType]::NVarChar)
[void]$command.Parameters.Add('@DESCRIPTION', [System.Data.SqlDbType]::NVarChar)
[void]$command.Parameters.Add('@COUPON', [System.Data.SqlDbType]::NVarChar)
[void]$command.Parameters.Add('@MATURITY', [System.Data.SqlDbType]::Date)
[void]$command.Parameters.Add('@DATEDDATE', [System.Data.SqlDbType]::Date)
[void]$command.Parameters.Add('@CALLDATE', [System.Data.SqlDbType]::Date)
[void]$command.Parameters.Add('@FIRSTCOUPON', [System.Data.SqlDbType]::NVarChar)
[void]$command.Parameters.Add('@CUSIP', [System.Data.SqlDbType]::NVarChar)
[void]$command.Parameters.Add('@PRICEYIELD', [System.Data.SqlDbType]::NVarChar)
[void]$command.Parameters.Add('@COM', [System.Data.SqlDbType]::NVarChar)
# I've defaulted to NVARCHAR here, but you should use the appropriate column data type

foreach ($row in $data) {
    # Set the values of each parameter
    $command.Parameters['@RATING'].Value      = $row.rating.trim()
    $command.Parameters['@PARVALUE'].Value    = $row."PAR VALUE".trim()
    $command.Parameters['@DESCRIPTION'].Value = $row.DESCRIPTION.trim()
    $command.Parameters['@COUPON'].Value      = $row.COUPON.trim()
    $command.Parameters['@MATURITY'].Value    = [datetime]$row.MATURITY
    $command.Parameters['@DATEDDATE'].Value   = [datetime]$row."DATED DATE"
    $command.Parameters['@CALLDATE'].Value    = [datetime]$row."CALL DATE"
    $command.Parameters['@FIRSTCOUPON'].Value = $row."FIRST COUPON"
    $command.Parameters['@CUSIP'].Value       = $row.CUSIP.trim()
    $command.Parameters['@PRICEYIELD'].Value  = $row."PRICE/YIELD".trim()
    $command.Parameters['@COM'].Value         = $row.COM.trim()

    [void]$command.ExecuteNonQuery()
}

Your code may vary slightly if you're using a different RDBMS than SQL Server.

If you're having trouble converting strings in $row into datetimes, you can use the ParseExact function:

$command.Parameters['@MATURITY'].Value    = [datetime]::ParseExact($row.MATURITY, 'dd.MM.yyyy', [cultureinfo]::InvariantCulture)

Or you can use Get-Date

$command.Parameters['@MATURITY'].Value    = Get-Date $row.MATURITY -Format 'dd.MM.yyyy'

The only complicated part of parameterized queries is that if you need to set a value to NULL in the databse, then the value of the parameter needs to be [System.DBNull]::Value, not $null.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.