Ошибка при импорте BACPAC-файла Azure в локальную базу данных из-за неправильного синтаксиса около EXTERNAL
При импорте файла DB из Azure BACPAC на локальный сервер SQL Server 2016 я получаю следующую ошибку.
Error SQL72014: .Net SqlClient Data Provider: Msg 102, Level 15, State 1, Line 1 Incorrect syntax near 'EXTERNAL'.
Error SQL72045: Script execution error. The executed script: CREATE EXTERNAL DATA SOURCE [BoxDataSrc]
WITH (
TYPE = RDBMS,
LOCATION = N'MYAZUREServer.database.windows.net',
DATABASE_NAME = N'MyAzureDb',
CREDENTIAL = [SQL_Credential]
);
(Microsoft.SqlServer.Dac)
7 ответов
Я столкнулся с этой же проблемой сегодня. Поскольку "WITH(TYPE = RDBMS)" применимо только к базе данных SQL Azure, мы получаем ошибку при попытке импортировать BACPAC в SQL Server 2017 на месте. Я нашел решение благодаря этой статье:
https://blogs.msdn.microsoft.com/azuresqldbsupport/2017/08/16/editing-a-bacpac-file/
Соответствующие шаги переписаны здесь:
- Сделайте копию файла bacpac (для безопасности в случае ошибок).
- Измените расширение файла на zip, затем распакуйте его в папку. Удивительно, но bacpac - это на самом деле просто zip-файл, а не что-то проприетарное и сложное.
Найдите файл model.xml и отредактируйте его, чтобы удалить раздел, который выглядит следующим образом:
<Element Type="SqlExternalDataSource" Name="[BoxDataSrc]"> <Property Name="DataSourceType" Value="1" /> <Property Name="Location" Value="MYAZUREServer.database.windows.net" /> <Property Name="DatabaseName" Value="MyAzureDb" /> <Relationship Name="Credential"> <Entry> <References Name="[SQL_Credential]" /> </Entry> </Relationship> </Element>
Если у вас есть несколько внешних источников данных этого типа, вам, вероятно, придется повторить шаг 3 для каждого из них. У меня был только один.
- Сохраните и закройте файл model.xml.
Теперь вам нужно заново сгенерировать контрольную сумму для model.xml, чтобы bacpac не думал, что она была подделана (поскольку вы только что подделали ее). Создайте файл PowerShell с именем computeHash.ps1 и вставьте в него этот код.
$modelXmlPath = Read-Host "model.xml file path" $hasher = [System.Security.Cryptography.HashAlgorithm]::Create("System.Security.Cryptography.SHA256CryptoServiceProvider") $fileStream = new-object System.IO.FileStream ` -ArgumentList @($modelXmlPath, [System.IO.FileMode]::Open) $hash = $hasher.ComputeHash($fileStream) $hashString = "" Foreach ($b in $hash) { $hashString += $b.ToString("X2") } $fileStream.Close() $hashString
Запустите сценарий PowerShell и укажите его путь к разархивированному и отредактированному файлу model.xml. Он вернет значение контрольной суммы.
Скопируйте значение контрольной суммы, затем откройте Origin.xml и замените существующую контрольную сумму ближе к нижней части строки, которая выглядит следующим образом:
<Checksum Uri="/model.xml">9EA0F06B282D4F42955C78A98822A31AA0ED0225CB131B8759379055A482D01F</Checksum>
Сохраните и закройте Origin.xml, затем выберите все файлы, поместите их в новый zip-файл и переименуйте расширение в bacpac.
Теперь вы можете использовать этот новый bacpac для импорта базы данных без получения ошибки. Это сработало для меня, это может сработать и для вас.
Согласно ответу @SQLDoug, это может произойти, если в вашей базе данных SQL Azure есть внешние таблицы (т. Е. Связанные таблицы из других баз данных). Вы можете проверить это в SSMS здесь:
Приложение к принятому ответу
Если вы удалите данные из этих внешних таблиц, вам также потребуется удалить элементы SqlExternalTable в файле model.xml, которые тоже использовали эти источники данных, они будут выглядеть примерно так:
<Element Type="SqlExternalTable" Name="[dbo].[DeliveryMethodsRestored]">
<Property Name="ExternalSchemaName" Value="dbo" />
<Property Name="ExternalObjectName" Value="DeliveryMethods" />
<Property Name="IsAnsiNullsOn" Value="True" />
<Property Name="IsQuotedIdentifierOn" Value="False" />
<Relationship Name="Columns">
<Entry>
<Element Type="SqlSimpleColumn" Name="[dbo].[DeliveryMethodsRestored].[DeliveryMethodId]">
<Property Name="IsNullable" Value="False" />
<Relationship Name="TypeSpecifier">
<Entry>
SNIP....
</Element>
Если вы выполните поиск по SqlExternalTable в model.xml, вы легко найдете их все.
Альтернативный подход к решению этой проблемы
Вместо того, чтобы исправлять BACPAC после его загрузки, другой способ справиться с этим - просто удалить внешние таблицы перед созданием BACPAC, то есть:
- Восстановите копию вашей базы данных в отдельную базу данных.
- Удалить внешние таблицы в восстановленной копии
- Удалить внешние источники данных в восстановленной копии
- Создайте BACPAC из этой восстановленной копии
- Удалить копию базы данных
Преимущество этого подхода состоит в том, что вы не создаете BACPAC из действующей базы данных, что, очевидно, "может привести к тому, что экспортированные данные таблицы будут несовместимыми, поскольку, в отличие от физического резервного копирования / восстановления SQL Server, экспорт не гарантирует согласованность транзакций".
Если это то, что вы, вероятно, сделаете так много, вы, вероятно, могли бы написать сценарии для автоматизации большинства вышеперечисленных шагов.
Тот же код ошибки с другой ошибкой.
Не удалось импортировать пакет. Предупреждение SQL72012: объект [PreProd_Data] существует в целевом объекте, но он не будет удален, даже если вы установили флажок "Создать операторы перетаскивания для объектов, которые находятся в целевой базе данных, но не находятся в источнике".
Предупреждение SQL72012: объект [PreProd_Log] существует в целевом объекте, но он не будет удален, даже если вы установили флажок "Создать операторы перетаскивания для объектов, которые находятся в целевой базе данных, но не находятся в источнике".
Ошибка SQL72014: поставщик данных.Net SqlClient: Msg 102, уровень 15, состояние 1, строка 5 Неправильный синтаксис рядом с "OPTIMIZE_FOR_AD_HOC_WORKLOADS".
Ошибка SQL72045: ошибка выполнения сценария. Выполняемый сценарий: ЕСЛИ СУЩЕСТВУЕТ (ВЫБРАТЬ 1 ИЗ [master].[Dbo].[Sysdatabases] WHERE [name] = N'$(DatabaseName)') BEGIN ALTER DATABASE SCOPED CONFIGURATION SET OPTIMIZE_FOR_AD_HOC_WORKLOADS = ON; КОНЕЦ
Решение
этот блог поможет отредактировать model.xml, чтобы удалить команду Relationship для OPTIMIZE_FOR_AD_HOC_WORKLOADS, которая не требуется в экземпляре SQL Server 2017.
https://blogs.msdn.microsoft.com/azuresqldbsupport/2017/08/16/editing-a-bacpac-file/
Сделайте копию файла BACPAC (для безопасности на случай ошибок). Измените расширение файла на zip, затем распакуйте его в папку. Удивительно, но на самом деле bacpac - это просто zip-файл, а не что-то проприетарное и труднодоступное. Найдите файл model.xml и отредактируйте его, чтобы удалить раздел, который выглядит следующим образом:
Соответствующие шаги переписаны здесь:
Сделайте копию файла BACPAC (для безопасности на случай ошибок).
Измените расширение файла на zip, затем распакуйте его в папку. Удивительно, но на самом деле bacpac - это просто zip-файл, а не что-то проприетарное и труднодоступное.
Найдите файл model.xml и отредактируйте его, чтобы удалить раздел, который выглядит следующим образом:
<Relationship Name="GenericDatabaseScopedConfigurationOptions"> <Entry> <References Name="[OPTIMIZE_FOR_AD_HOC_WORKLOADS]" /> </Entry> </Relationship>
Удалите следующий блок из model.xml
<Element Type="SqlGenericDatabaseScopedConfigurationOptions" Name="[OPTIMIZE_FOR_AD_HOC_WORKLOADS]"> <Property Name="GenericValueType" Value="2" /> <Property Name="GenericValue" Value="ON" /> </Element>
Сохраните и закройте model.xml.
Теперь вам нужно повторно сгенерировать контрольную сумму для model.xml, чтобы бакпак не думал, что он был подделан (поскольку вы только что подделали его). Создайте файл PowerShell с именем computeHash.ps1 и поместите в него этот код.
Запустите сценарий PowerShell и укажите путь к распакованному и отредактированному файлу model.xml. Он вернет значение контрольной суммы.
Скопируйте значение контрольной суммы, затем откройте Origin.xml и замените существующую контрольную сумму.
Сохраните и закройте Origin.xml, затем выберите все файлы и поместите их в новый zip-файл и переименуйте расширение в bacpac.
Теперь файл bacpack готов к импорту, и он работает для меня.
Спасибо.
Я столкнулся с той же проблемой при импорте файла Azure SQL .bacpac (в котором был создан внешний источник данных) в локальный SQL 2019 с использованием последней версии SSMS (19.1).
Поддержка внешних источников данных предусмотрена в SQL 2022, поэтому после обновления до SQL 2022 с SQL 2019 проблема была решена.
Поэтому всегда используйте последнюю версию SSMS при импорте bacpac и проверяйте, поддерживаются ли функции Azure SQL на локальном SQL-сервере или нет.
Запросы к базе данных Elastic поддерживаются только в базе данных SQL Azure v12 или более поздней версии, но не на локальном сервере. https://msdn.microsoft.com/en-us/library/dn935022.aspx
Я получил тот же код ошибки (SQL72045) при импорте bacpac, хотя мы удалили внешние источники данных в Azure, с которыми мы синхронизировались. Оказалось, что осталась процедура «TransferDo» со ссылкой на SCOPED CREDENTIAL для другой базы данных. После того, как мы удалили процедуру, импорт работал нормально.
Для тех, кто следит за ответом SQLDoug и получает ужасныйFile contains corrupted data
после после обновленияChecksum
стоимость вOrigin.xml
, есть более простой способ, который вообще не требует изменения файла.
- Переименуйте свой в .
zip
- Откройте свой
.zip
файл и скопируйте файл в локальный каталог - Измените скопированное
model.xml
файл по мере необходимости. - Если он у вас еще не установлен, приобретите себе копию
sqlpackage.exe
отсюда . _Самый простой способ установить последнюю версию — просто запустить
dotnet tool install -g microsoft.sqlpackage
- Теперь просто выполните:
sqlpackage /Action:Import /SourceFile:”blahblahblah.bacpac” /TargetDatabaseName:TargetDBName /TargetServerName:localhost /TargetUser:sa /TargetPassword:SQLPassword /ModelFilePath:”model.xml” /TargetTrustServerCertificate:True
- Восстановление будет выполнено без необходимости иметь дело с какими-либо проблемами «поврежденного файла» или возможными задержками при распаковке/сжатии содержимого.
.bacpac
файл.