Я пытаюсь автоматизировать вставку значений из CSV в таблицу базы данных SQL. Все отлично переносится в базу данных, за исключением имен с апострофами. Я попытался добавить второй апостроф рядом с первым в надежде, что он ускользнет, но безуспешно.
Ошибка, которую я получаю, выглядит следующим образом:
Exception calling "ExecuteReader" with "0" argument(s): "Incorrect syntax near 'BRIEN'.
Incorrect syntax near 'BRIEN'.
Unclosed quotation mark after the character string '
WHERE NPINum = (something);
END
'."
At C:\REAL SCRIPTING HOURS\NPI\NPI-SQL.ps1:232 char:13
+ $SqlDataReader = $SqlCommand.ExecuteReader();
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SqlException
Раздел, в котором возникают проблемы, выглядит следующим образом (простите за беспорядок):
$csvData = Import-Csv -Path $moveToSQL.Item($iterator)
$correctCols = $csvData | Select-Object 'NPI', 'Provider Last Name (Legal Name)', 'Provider First Name', 'Provider Middle Name', 'Provider Credential Text'
## Get it into SQL
for ($i = 0; $i -lt $correctCols.Count; $i++) {
## Make sure there are no issues with apostrophe'd names (I know there's likely a more visually appealing way of doing this... but alas)
$apostropheCheck = 0
## Check the last name listed
$apostropheCheck = $correctCols.Get($i).'Provider Last Name (Legal Name)'.Contains("'") # bool to see if an apostrophe even exists
if ($apostropheCheck -eq 'True') {
# if it does, do something
$apostropheCheck = $correctCols.Get($i).'Provider Last Name (Legal Name)'.IndexOf("'") # get the index of where the apostrophe is
$correctCols.Get($i).'Provider Last Name (Legal Name)'.Insert($apostropheCheck, "'") # add in another one for good measure (break out)
} # rinse and repeat
## Check the first name listed
$apostropheCheck = $correctCols.Get($i).'Provider First Name'.Contains("'")
if ($apostropheCheck -eq 'True') {
$apostropheCheck = $correctCols.Get($i).'Provider First Name'.IndexOf("'")
$correctCols.Get($i).'Provider First Name'.Insert($apostropheCheck, "'")
}
## Check the middle name listed
$apostropheCheck = $correctCols.Get($i).'Provider Middle Name'.Contains("'")
if ($apostropheCheck -eq 'True') {
$apostropheCheck = $correctCols.Get($i).'Provider Middle Name'.IndexOf("'")
$correctCols.Get($i).'Provider Middle Name'.Insert($apostropheCheck, "'")
}
## Create query to run
$SqlQuery = "
IF NOT EXISTS (SELECT 1 FROM (my.dbo.table) WHERE NPINum = {0})
BEGIN
INSERT INTO (my.dbo.table)
VALUES
('{0}'
,'{1}'
,'{2}'
,'{3}'
,'{4}')
END
ELSE
IF NOT EXISTS
(SELECT 1 FROM (my.dbo.table)
WHERE NPINum = {0} AND LastName = '{1}'
AND FirstName = '{2}'
AND MiddleName = '{3}'
AND Credentials = '{4}')
BEGIN
UPDATE (my.dbo.table)
SET LastName = '{1}', FirstName = '{2}', MiddleName = '{3}', Credentials = '{4}'
WHERE NPINum = {0};
END
" -f $correctCols.Get($i).NPI, $correctCols.Get($i).'Provider Last Name (Legal Name)', $correctCols.Get($i).'Provider First Name', $correctCols.Get($i).'Provider Middle Name', $correctCols.Get($i).'Provider Credential Text'
$SqlCommand.CommandText = $SqlQuery
## Open up SQL communication and execute query in the database
$SqlConnection.Open()
$SqlDataReader = $SqlCommand.ExecuteReader()
$SqlConnection.Close()
}
Прошу прощения, я новичок в PowerShell и относительно новичок в SQL. Не могли бы вы объяснить, почему? Кроме того, поможет ли это решить проблему, с которой я столкнулся?
избегает SQL-инъекций и уже обрабатывает экранирование '
за вас
Рекомендуется избегать String.Format
(-f
) любой ценой. Ручная интерполяция значений в строке запроса открывается для атак SQL-инъекций.
Вместо этого вам следует использовать метод .AddWithValue из класса SqlParameter, таким образом API будет обрабатывать интерполяцию значений за вас, избегая этой уязвимости и обрабатывая правильное экранирование знаков препинания (т.е.: обработку проблема, с которой вы столкнулись, избегая одинарных кавычек '
).
Вот как более или менее должен выглядеть ваш код. Я значительно уменьшаю количество параметров, которые нужно ввести здесь, чтобы дать упрощенный ответ. Ответ также предполагает, что в вашем CSV есть столбцы Foo
, Bar
, Baz
.
$command = [System.Data.SqlClient.SqlCommand]::new()
$command.Connection = $connection # <= SQLConnection object needs to be defined beforehand
$command.CommandText = @'
IF NOT EXISTS (SELECT 1 FROM (my.dbo.table) WHERE NPINum = @foo)
BEGIN
INSERT INTO (my.dbo.table)
VALUES (@foo, @bar, @baz)
END
ELSE
IF NOT EXISTS
(SELECT 1 FROM (my.dbo.table)
WHERE NPINum = @foo AND LastName = @bar
AND FirstName = @baz)
BEGIN
UPDATE (my.dbo.table)
SET LastName = @bar, FirstName = @baz
WHERE NPINum = @foo;
END
'@
try {
$command.Connection.Open()
foreach ($line in $csv) {
try {
$command.Parameters.Clear()
$null = $command.Parameters.AddWithValue('@foo', $line.Foo)
$null = $command.Parameters.AddWithValue('@bar', $line.Bar)
$null = $command.Parameters.AddWithValue('@baz', $line.Baz)
$reader = $command.ExecuteReader()
}
catch {
# handle possible writing errors here
}
}
}
finally {
if ($command.Connection) {
$command.Connection.Dispose()
$command.Dispose()
}
}
Ужасная идея использовать
String.Format
(-f
) вместо.Parameters.AddWithValue(...)
в вашем запросе.