[英]Using “SELECT INTO” with Azure SQL to copy data from another DB
我正在尝试在Azure上自动初始化SQL DB。 对于某些(查找)表,每次初始化时都需要将数据从源DB复制到新DB中。
为此,我执行一个包含的查询
SELECT * INTO [target_db_name]..[my_table_name] FROM [source_db_name].dbo.[my_table_name]
此时抛出异常告诉我
此版本的SQL Server不支持在“source_db_name.dbo.my_table_name”中引用数据库和/或服务器名称。
仔细研究过这个,我发现现在可以引用另一个Azure SQL DB,前提是它已被配置为外部数据源。 [ 这里和这里 ]
所以,在我的目标数据库中,我执行了以下语句:
CREATE MASTER KEY ENCRYPTION BY PASSWORD = '<password>';
CREATE DATABASE SCOPED CREDENTIAL cred
WITH IDENTITY = '<username>',
SECRET = '<password>';
CREATE EXTERNAL DATA SOURCE [source_db_name]
WITH
(
TYPE=RDBMS,
LOCATION='my_location.database.windows.net',
DATABASE_NAME='source_db_name',
CREDENTIAL= cred
);
CREATE EXTERNAL TABLE [dbo].[my_table_name](
[my_column_name] BIGINT NOT NULL
)
WITH
(
DATA_SOURCE = [source_db_name],
SCHEMA_NAME = 'dbo',
OBJECT_NAME = 'my_table_name'
)
但SELECT INTO
语句仍会产生相同的异常。
此外,简单的SELECT * FROM [source_db_name].[my_table_name]
产生异常“无效的对象名称'source_db_name.my_table_name'”。
我错过了什么?
UPDATE
我发现了问题: CREATE EXTERNAL TABLE
创建了目标数据库中似乎是一个表的内容。 要查询此信息,不应使用源DB名称。 所以我失败了:
SELECT * FROM [source_db_name].[my_table_name]
我知道我应该真的在查询
SELECT * FROM [my_table_name]
看起来您可能需要根据看似正确的语法来定义外部表:
CREATE EXTERNAL TABLE [dbo].[source_table](
...
)
WITH
(
DATA_SOURCE = source_db_name
);
现在,由于您正在创建外部表,因此查询可以假装外部表是我们[target_db]的本机对象 - 这允许您编写查询SELECT * FROM [my_table_name]
,正如您从编辑中发现的那样。 从文档中,重要的是要注意“这允许对远程数据库进行只读查询”。 所以,这个表对象不可写,但你的问题只是提到从中读取以填充新表。
正如所承诺的,这是我如何处理SQL Server的数据库部署。 我在Azure中的VM上使用相同的方法用于本地,Windows Azure SQL数据库或SQL。 它花了很多痛苦,试验和错误。
这一切都始于SQL Server数据工具,SSDT如果你还没有使用SSDT来管理数据库作为一个独立于你的应用程序的项目,你需要。 在这里抓一份。 如果您已在计算机上运行Visual Studio版本,则可以获得特定于该版本Visual Studio的SSDT版本。 如果你还没有运行VS,那么你可以抓住SSDT,它将安装最小的Visual Studio组件来让你前进。
然后,右键单击数据库项目并选择Import - > Database。
现在,您可以指向数据库的当前开发副本,并将其模式导入到项目中。 此过程将从源数据库中提取所有表,视图,存储过程,函数等。 完成后,您将看到如下图所示的内容。
导入的每个模式都有一个文件夹,以及用于定义数据库中模式的安全性文件夹。 浏览这些文件夹并查看创建的文件。
您会发现创建的所有脚本都是CREATE脚本。 这对于管理项目很重要。 您现在可以保存新的解决方案,然后将其检入当前的源控制系统。 这是您的初始提交。
这是管理数据库项目的新思维过程。 当您需要进行架构更改时,您将进入此项目以更改这些create语句以定义您希望该对象的状态。 您总是在模式中创建CREATE语句,而不是ALTER语句。 看看下面的例子。
更新表格假设我们已决定开始跟踪我们的dbo.ETLProcess表格中的更改。 我们需要列来跟踪CreatedDateTime,CreatedByID,LastUpdatedDateTime和LastUpdatedByID。 打开dbo \\ Tables文件夹中的dbo.ETLProcess文件,您将看到该表的当前版本如下所示:
CREATE TABLE [dbo].[ETLProcess] (
[ETLProcessID] INT IDENTITY (1, 1) NOT NULL
, [TenantID] INT NOT NULL
, [Name] NVARCHAR (255) NULL
, [Description] NVARCHAR (1000) NULL
, [Enabled] BIT DEFAULT ((1)) NOT NULL
, CONSTRAINT [PK_ETLProcess__ETLProcessID_TenantID]
PRIMARY KEY CLUSTERED ([ETLProcessID], [TenantID])
, CONSTRAINT [FK_ETLProcess_Tenant__TenantID]
FOREIGN KEY ([TenantID])
REFERENCES [dbo].[Tenant] ([TenantID])
);
要记录我们想要进行的更改,我们只需将列添加到表中,如下所示:
CREATE TABLE [dbo].[ETLProcess] (
[ETLProcessID] INT IDENTITY (1, 1) NOT NULL
, [TenantID] INT NOT NULL
, [Name] NVARCHAR (255) NULL
, [Description] NVARCHAR (1000) NULL
, [Enabled] BIT DEFAULT ((1)) NOT NULL
, [CreatedDateTime] DATETIME DEFAULT(GETUTCDATE())
, [CreatedByID] INT
, [LastUpdatedDateTime] DATETIME DEFAULT(GETUTCDATE())
, [LastUpdatedByID] INT
, CONSTRAINT [PK_ETLProcess__ETLProcessID_TenantID]
PRIMARY KEY CLUSTERED ([ETLProcessID], [TenantID])
, CONSTRAINT [FK_ETLProcess_Tenant__TenantID]
FOREIGN KEY ([TenantID])
REFERENCES [dbo].[Tenant] ([TenantID])
);
我没有在定义中添加任何外键,但是如果你想创建它们,你可以将它们添加到租户的外键下面。 对文件进行更改后,保存。
接下来您要养成的习惯是检查数据库以确保它有效。 在编程世界中,您将运行测试构建以确保它编译。 在这里,我们做了非常相似的事情。 从主菜单点击Build - > Build Database1(我们的数据库项目的名称)。
输出窗口将打开并告诉您项目是否有任何问题。 在这里您可以看到外键引用尚不存在的表,创建对象语句中的语法错误等等。在检查更新到源代码管理之前,您需要清理它们。 在将更改部署到开发环境之前,您必须先修复它们。
成功构建数据库项目并将其签入源代码控制后,您就可以进行下一个更改过程。
部署更改我之前告诉过您,记住所有模式语句都是CREATE语句非常重要。 原因如下:SSDT为您提供了两种将更改部署到目标实例的方法。 他们都使用这些create语句来比较您的项目与目标。 通过比较两个create语句,它可以生成使目标实例与项目保持同步所需的ALTER语句。
部署这些更改的两个选项是T-SQL更改脚本或dacpac。 基于原始帖子,听起来更改脚本将是最熟悉的。
默认情况下,您的数据库项目将是左侧的源。 单击右侧的“选择目标”,然后选择要“升级”的数据库实例。 然后单击左上角的Compare,SSDT将比较项目的状态和目标数据库。
然后,您将获得目标数据库中不在项目中的所有对象的列表(在DROP部分中),项目和目标数据库之间的所有对象的列表(在ALTER部分中),以及项目中但尚未在目标数据库中的对象列表(在ADD部分中)。
有时您会看到列出的更改,您不想进行更改(对象名称的Casing更改,或默认语句周围的括号数。您可以取消选择此类更改。其他时候您将不会准备好在目标部署中部署这些更改,您也可以取消选择这些更改。如果您选择更新(下面的红色框),或者添加到您的更改脚本(下面的绿框),则所有选中的项目都将在目标数据库中更改,如果您点击“生成脚本”图标。
处理数据库项目中的查找数据现在我们终于回答您的原始问题,如何将查找数据部署到目标数据库。 在数据库项目中,您可以在解决方案资源管理器中右键单击该项目,然后选择添加 - >新项。 你会得到一个对话框。 在左侧,单击User Scripts,然后在右侧,选择Post-Deployment Script。
通过添加此类型的脚本,SSDT知道您希望在任何架构更改后运行此步骤。 这是您输入查找值的地方,因此它们包含在源代码管理中!
现在,这是关于这些部署后脚本的非常重要的注意事项。 如果在新数据库中调用脚本,在现有数据库中调用脚本,或者连续调用100次,则需要确保此处添加的任何T-SQL都能正常工作。 由于这个要求,我已经在merge语句中包含了所有的查找值。 这样我就可以处理插入,更新和删除。
在将此文件提交给源代码控制之前,请在上述所有三种情况下对其进行测试,以确保它不会失败。
总结一下从直接在目标环境中进行更改到使用SSDT和控制更改的源代码是软件开发生命周期成熟的重要一步。 好消息是,它使您能够以与持续集成/持续部署方法兼容的方式将数据库视为部署过程的一部分。
一旦习惯了新流程,您就可以学习如何将从SSDT生成的dacpac添加到部署脚本中,并在部署中的恰当时间推送更改。
它还可以让您摆脱SELECT INTO问题,原始问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.