是否有“脚本表为 - MERGE”?在某处起作用?

发布于 2024-10-21 02:30:32 字数 159 浏览 0 评论 0原文

在 SSMS 2008 R2 中,当我右键单击表时,我会看到“脚本表为”,然后是插入和更新选项。但是合并呢?合并实际上就是将这两者结合在一起。

我可以获得任何可以添加该选项的工具吗? (因此,我可以编写一个合并语句,准备好添加源信息(有点像插入和更新脚本已准备好添加要插入或更新的数据)。

In SSMS 2008 R2, when I right click on a table I see "Script Table as" then options for Insert and Update. But what about Merge? Merge is really just the two of these together.

Is there any tool I can get that will add that option? (So I can script a merge statement ready for me to add in source information (kind of like the Insert and Update scripts are ready for adding the data to insert or update).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

苏别ゝ 2024-10-28 02:30:32

SSMS 中没有执行此类操作的内置功能(我想通过外部插件可能可以实现)。

有一个程序 sp_GenMerge(根据 MIT 许可证授权)由 Michał Gołoś 允许使用数据编写表脚本作为合并语句。

示例场景:

CREATE TABLE [Customer]  (
   ID                   INT                  IDENTITY(1,1) CONSTRAINT PK_CUSTOMER PRIMARY KEY (ID),
   FIRSTNAME            NVARCHAR(30)         NOT NULL,
   LASTNAME             NVARCHAR(30)         NOT NULL,
   CITY                 NVARCHAR(30)         NULL,
   COUNTRY              NVARCHAR(30)         NULL,
   PHONE                NVARCHAR(20)         NULL
);

INSERT INTO [Customer] ([FirstName],[LastName],[City],[Country],[Phone])
VALUES('John','Smith','Berlin','Germany','12345'),('Cathrine','Fa','Brasilia','Brasil','(3) 4324-4723');

基本 SP 调用(它支持更多选项 - 请参阅文档):

EXEC sp_GenMerge @source_table = 'dbo.Customer';

输出:

DECLARE @xml XML = N'
<!-- Insert the generated data here -->
';


MERGE INTO dbo.Customer AS Target
USING (SELECT x.value('(@ID)', 'int') AS [ID]
            , x.value('(@FIRSTNAME)', 'nvarchar(30)') AS [FIRSTNAME]
            , x.value('(@LASTNAME)', 'nvarchar(30)') AS [LASTNAME]
            , x.value('(@CITY)', 'nvarchar(30)') AS [CITY]
            , x.value('(@COUNTRY)', 'nvarchar(30)') AS [COUNTRY]
            , x.value('(@PHONE)', 'nvarchar(20)') AS [PHONE]
        FROM @xml.nodes('v') AS t(x)) AS Source ([ID], [FIRSTNAME], [LASTNAME], [CITY], [COUNTRY], [PHONE])
  ON (Target.[ID] = Source.[ID])
WHEN NOT MATCHED BY TARGET
THEN INSERT([FIRSTNAME]
          , [LASTNAME]
          , [CITY]
          , [COUNTRY]
          , [PHONE])
     VALUES(Source.[FIRSTNAME]
          , Source.[LASTNAME]
          , Source.[CITY]
          , Source.[COUNTRY]
          , Source.[PHONE])
WHEN MATCHED AND EXISTS (SELECT Target.[FIRSTNAME]
                              , Target.[LASTNAME]
                              , Target.[CITY]
                              , Target.[COUNTRY]
                              , Target.[PHONE]
                         EXCEPT
                         SELECT Source.[FIRSTNAME]
                              , Source.[LASTNAME]
                              , Source.[CITY]
                              , Source.[COUNTRY]
                              , Source.[PHONE])
THEN UPDATE SET Target.[FIRSTNAME] = Source.[FIRSTNAME]
              , Target.[LASTNAME] = Source.[LASTNAME]
              , Target.[CITY] = Source.[CITY]
              , Target.[COUNTRY] = Source.[COUNTRY]
              , Target.[PHONE] = Source.[PHONE];
GO

并将脚本行作为 XML 有效负载:

<v ID="1" FIRSTNAME="John" LASTNAME="Smith" CITY="Berlin" COUNTRY="Germany" PHONE="12345" />
<v ID="2" FIRSTNAME="Cathrine" LASTNAME="Fa" CITY="Brasilia" COUNTRY="Brasil" PHONE="(3) 4324-4723" />

There is no built-in functionality in SSMS that performs such operation(I guess it may be possible with external plugin).

There is a procedure sp_GenMerge(licensed under MIT license) written by Michał Gołoś that allows to script table with data as merge statement.

Sample scenario:

CREATE TABLE [Customer]  (
   ID                   INT                  IDENTITY(1,1) CONSTRAINT PK_CUSTOMER PRIMARY KEY (ID),
   FIRSTNAME            NVARCHAR(30)         NOT NULL,
   LASTNAME             NVARCHAR(30)         NOT NULL,
   CITY                 NVARCHAR(30)         NULL,
   COUNTRY              NVARCHAR(30)         NULL,
   PHONE                NVARCHAR(20)         NULL
);

INSERT INTO [Customer] ([FirstName],[LastName],[City],[Country],[Phone])
VALUES('John','Smith','Berlin','Germany','12345'),('Cathrine','Fa','Brasilia','Brasil','(3) 4324-4723');

Basic SP call(it supports more options - see doc):

EXEC sp_GenMerge @source_table = 'dbo.Customer';

Output:

DECLARE @xml XML = N'
<!-- Insert the generated data here -->
';


MERGE INTO dbo.Customer AS Target
USING (SELECT x.value('(@ID)', 'int') AS [ID]
            , x.value('(@FIRSTNAME)', 'nvarchar(30)') AS [FIRSTNAME]
            , x.value('(@LASTNAME)', 'nvarchar(30)') AS [LASTNAME]
            , x.value('(@CITY)', 'nvarchar(30)') AS [CITY]
            , x.value('(@COUNTRY)', 'nvarchar(30)') AS [COUNTRY]
            , x.value('(@PHONE)', 'nvarchar(20)') AS [PHONE]
        FROM @xml.nodes('v') AS t(x)) AS Source ([ID], [FIRSTNAME], [LASTNAME], [CITY], [COUNTRY], [PHONE])
  ON (Target.[ID] = Source.[ID])
WHEN NOT MATCHED BY TARGET
THEN INSERT([FIRSTNAME]
          , [LASTNAME]
          , [CITY]
          , [COUNTRY]
          , [PHONE])
     VALUES(Source.[FIRSTNAME]
          , Source.[LASTNAME]
          , Source.[CITY]
          , Source.[COUNTRY]
          , Source.[PHONE])
WHEN MATCHED AND EXISTS (SELECT Target.[FIRSTNAME]
                              , Target.[LASTNAME]
                              , Target.[CITY]
                              , Target.[COUNTRY]
                              , Target.[PHONE]
                         EXCEPT
                         SELECT Source.[FIRSTNAME]
                              , Source.[LASTNAME]
                              , Source.[CITY]
                              , Source.[COUNTRY]
                              , Source.[PHONE])
THEN UPDATE SET Target.[FIRSTNAME] = Source.[FIRSTNAME]
              , Target.[LASTNAME] = Source.[LASTNAME]
              , Target.[CITY] = Source.[CITY]
              , Target.[COUNTRY] = Source.[COUNTRY]
              , Target.[PHONE] = Source.[PHONE];
GO

And scripted rows as XML payload:

<v ID="1" FIRSTNAME="John" LASTNAME="Smith" CITY="Berlin" COUNTRY="Germany" PHONE="12345" />
<v ID="2" FIRSTNAME="Cathrine" LASTNAME="Fa" CITY="Brasilia" COUNTRY="Brasil" PHONE="(3) 4324-4723" />
眼波传意 2024-10-28 02:30:32

GitHub 上有一个非常有用的脚本,我一直在使用它并取得了巨大的成功。

使用表数据生成 SQL MERGE 语句< /a>

用例:

  • 生成静态数据表的语句,将 .SQL 文件存储在源代码管理中/将其添加到 Visual Studio 数据库项目并将其用作开发/测试/生产部署的一部分。生成的语句是可重新运行的,因此您可以对文件进行更改并轻松在环境之间迁移这些更改。
  • 从生产表生成语句,然后在开发/测试环境中运行这些语句。将此安排为 SQL 作业的一部分,以保持所有环境同步。
  • 将测试数据输入您的开发环境,然后从开发表生成语句,以便您始终可以使用有效的示例数据重现测试数据库。

它是如何工作的?
生成的 MERGE 语句填充目标表以匹配源数据。这包括删除源中不存在的任何多余行。

当执行生成的 MERGE 语句时,根据是否找到匹配来应用以下逻辑:

  • 如果目标表中不存在源行,则执行 INSERT
  • 如果目标表中的给定行不存在于目标表中源,执行 DELETE
  • 如果源行已存在于目标表中并且已更改,则执行 UPDATE
  • 如果源行已存在于目标表中但数据未更改,则不执行任何操作(可配置)

用法:

  1. 确保您的 SQL 客户端配置为将结果发送到网格。
  2. 执行过程,提供源表名称作为参数
  3. 单击结果集中的超链接。
  4. 复制 SQL(不包括输出标记)并粘贴到新的查询窗口中以执行。

示例:
要生成包含 Person.AddressType 表中所有数据(不包括 ModifiedDate 和 rowguid 列)的 MERGE 语句:

EXEC AdventureWorks.dbo.sp_generate_merge @schema = 'Person', @table_name ='AddressType', @cols_to_exclude = '''ModifiedDate'',''rowguid'''

输出:

SET NOCOUNT ON
GO 
SET IDENTITY_INSERT [Person].[AddressType] ON
GO
MERGE INTO [Person].[AddressType] AS Target
USING (VALUES
  (1,'Billing')
 ,(2,'Home')
 ,(3,'Main Office')
 ,(4,'Primary')
 ,(5,'Shipping')
 ,(6,'Contact')
) AS Source ([AddressTypeID],[Name])
ON (Target.[AddressTypeID] = Source.[AddressTypeID])
WHEN MATCHED AND (
    NULLIF(Source.[Name], Target.[Name]) IS NOT NULL OR NULLIF(Target.[Name], Source.[Name]) IS NOT NULL) THEN
 UPDATE SET
 [Name] = Source.[Name]
WHEN NOT MATCHED BY TARGET THEN
 INSERT([AddressTypeID],[Name])
 VALUES(Source.[AddressTypeID],Source.[Name])
WHEN NOT MATCHED BY SOURCE THEN 
 DELETE;

SET IDENTITY_INSERT [Person].[AddressType] OFF
GO
SET NOCOUNT OFF
GO

There is a very useful script on GitHub that I've been using with great success.

Generate SQL MERGE statements with Table data

Use Cases:

  • Generate statements for static data tables, store the .SQL file in source control/add it to a Visual Studio Database Project and use it as part of your Dev/Test/Prod deployments. The generated statements are re-runnable, so you can make changes to the file and easily migrate those changes between environments.
  • Generate statements from your Production tables and then run those statements in your Dev/Test environments. Schedule this as part of a SQL Job to keep all of your environments in-sync.
  • Enter test data into your Dev environment, and then generate statements from the Dev tables so that you can always reproduce your test database with valid sample data.

How Does It Work?
The generated MERGE statement populates the target table to match the source data. This includes the removal of any excess rows that are not present in the source.

When the generated MERGE statement is executed, the following logic is applied based on whether a match is found:

  • If the source row does not exist in the target table, an INSERT is performed
  • If a given row in the target table does not exist in the source, a DELETE is performed
  • If the source row already exists in the target table and has changed, an UPDATE is performed
  • If the source row already exists in the target table but the data has not changed, no action is performed (configurable)

Usage:

  1. Ensure that your SQL client is configured to send results to grid.
  2. Execute the proc, providing the source table name as a parameter
  3. Click the hyperlink within the result set.
  4. Copy the SQL (excluding the Output tags) and paste into a new query window to execute.

Example:
To generate a MERGE statement containing all data within the Person.AddressType table, excluding the ModifiedDate and rowguid columns:

EXEC AdventureWorks.dbo.sp_generate_merge @schema = 'Person', @table_name ='AddressType', @cols_to_exclude = '''ModifiedDate'',''rowguid'''

OUTPUT:

SET NOCOUNT ON
GO 
SET IDENTITY_INSERT [Person].[AddressType] ON
GO
MERGE INTO [Person].[AddressType] AS Target
USING (VALUES
  (1,'Billing')
 ,(2,'Home')
 ,(3,'Main Office')
 ,(4,'Primary')
 ,(5,'Shipping')
 ,(6,'Contact')
) AS Source ([AddressTypeID],[Name])
ON (Target.[AddressTypeID] = Source.[AddressTypeID])
WHEN MATCHED AND (
    NULLIF(Source.[Name], Target.[Name]) IS NOT NULL OR NULLIF(Target.[Name], Source.[Name]) IS NOT NULL) THEN
 UPDATE SET
 [Name] = Source.[Name]
WHEN NOT MATCHED BY TARGET THEN
 INSERT([AddressTypeID],[Name])
 VALUES(Source.[AddressTypeID],Source.[Name])
WHEN NOT MATCHED BY SOURCE THEN 
 DELETE;

SET IDENTITY_INSERT [Person].[AddressType] OFF
GO
SET NOCOUNT OFF
GO
っ〆星空下的拥抱 2024-10-28 02:30:32

直到我知道你不能,但有一些提示:

如何编辑SSMS 脚本表作为模板?

Until i know you can´t but there are some tips:

How to edit SSMS Script Table As templates?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文