Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 如何为不同的源数据库/表版本编写T-SQL脚本_Sql Server - Fatal编程技术网

Sql server 如何为不同的源数据库/表版本编写T-SQL脚本

Sql server 如何为不同的源数据库/表版本编写T-SQL脚本,sql-server,Sql Server,我的主要问题是: 如果源表没有包含它可能具有的所有字段,如何编写可以处理的insert SQL查询。有关原因,请参见“背景”一节 因此,我的目标表有一组已知的字段,但我的源表可能缺少其中一些字段。像这样: Destination.TableA ---------- ID Field 1 Field 2 Field 3 source1.TableA ----- ID Field 2 source2.TableA ------------- ID Field 1 Field 2 所以我基本上需

我的主要问题是: 如果源表没有包含它可能具有的所有字段,如何编写可以处理的insert SQL查询。有关原因,请参见“背景”一节

因此,我的目标表有一组已知的字段,但我的源表可能缺少其中一些字段。像这样:

Destination.TableA
----------
ID
Field 1
Field 2
Field 3

source1.TableA
-----
ID
Field 2

source2.TableA
-------------
ID
Field 1
Field 2
所以我基本上需要的是一个等价于if的字段。。。存在,然后插入到。。。。主键不应受到影响

我知道如何测试表或其他SQL对象的存在性,但我不知道如何在有关表字段的insert语句中进行测试。-你能给我一个提示吗

一点背景: 我们有很多客户运行我们产品的不同版本。随着时间的推移,我们的数据库已经一个接一个地扩展。一些客户数据库已根据这些客户的个人需求进行了定制

现在,我正在开发一个工具/脚本,将所有这些旧版本升级到当前的数据库版本。由于我们对最新版本进行了重构,因此此次升级需要大量修补/移动数据,因此我想构建一个能够升级源数据库所有版本的脚本。-这主要是为了在开发脚本时避免重复调整

因为我已经有了生成SQL查询的工具,所以生成的查询代码的数量是其功能的次要部分

p、 在这次升级之后,我们已经有了内置的升级机制来简化将来的升级。本脚本旨在更新我们2018年前的所有产品,使其进入我们的新产品/升级周期


p、 另外,所有数据库都运行在Microsoft SQL Server上

好的,这将是一个相当混乱的答案,因为这里有很多事情可以让它以合理合理的方式工作。我使用合并和动态SQL生成脚本,然后为每个表运行它们

首先,我需要一些测试数据,所以我创建了一个临时数据库来使用:

USE Temp;
GO
CREATE SCHEMA destination;
GO
CREATE SCHEMA source1;
GO
CREATE SCHEMA source2
GO
CREATE TABLE destination.tableA (
    ID INT,
    Field1 VARCHAR(50),
    Field2 VARCHAR(50),
    Field3 VARCHAR(50));
GO
CREATE TABLE source1.tableA (
    ID INT,
    Field2 VARCHAR(50));
GO
CREATE TABLE source2.tableA (
    ID INT,
    Field1 VARCHAR(50),
    Field2 VARCHAR(50));
GO
然后我添加了一些测试数据,使其可重复:

DELETE FROM destination.tableA;
DELETE FROM source1.tableA;
DELETE FROM source2.tableA;
INSERT INTO source1.tableA SELECT 1, 'dog';
INSERT INTO source1.tableA SELECT 2, 'cat';
INSERT INTO source2.tableA SELECT 1, 'dog', 'harold';
INSERT INTO source2.tableA SELECT 3, 'mouse', 'midge';
GO
计划是从一个完全空的目标表开始,在某些情况下,所有数据都来自一个表,而在其他情况下,数据是混合的,例如,一个表提供一段数据,在另一个表中为同一主键设置另一列。这使得事情变得更加复杂,因为现在我们需要根据数据进行插入或更新。这就是合并的意义所在

我还使用FOR XML PATH获取逗号分隔的列表。下面是令人讨厌的动态SQL:

IF OBJECT_ID('tempdb..#schemas') IS NOT NULL
    DROP TABLE #schemas;
GO
SELECT SCHEMA_NAME INTO #schemas FROM INFORMATION_SCHEMA.SCHEMATA WHERE CATALOG_NAME = 'Temp' AND SCHEMA_NAME LIKE 'source%';
WHILE EXISTS (SELECT * FROM #schemas)
BEGIN
    DECLARE @schema VARCHAR(50);
    SELECT TOP 1 @schema = SCHEMA_NAME FROM #schemas;
    SELECT @schema;
    DECLARE @sql NVARCHAR(4000);
    SELECT @sql = N'MERGE destination.tableA AS [target] USING (SELECT * FROM ' + QUOTENAME(@schema) + '.tableA) 
        AS [source] (' 
        + STUFF((SELECT ',' + COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG = 'Temp' AND TABLE_SCHEMA = @schema AND TABLE_NAME = 'TableA' ORDER BY ORDINAL_POSITION FOR XML PATH('')), 1, 1, '')
        + N') ON [target].ID = [source].ID
        WHEN MATCHED THEN UPDATE SET '
        + STUFF((SELECT ',' + COLUMN_NAME + ' = [source].' + COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG = 'Temp' AND TABLE_SCHEMA = @schema AND TABLE_NAME = 'TableA' AND COLUMN_NAME != 'ID' ORDER BY ORDINAL_POSITION FOR XML PATH('')), 1, 1, '')
        + N' WHEN NOT MATCHED THEN INSERT ('
        + STUFF((SELECT ',' + COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG = 'Temp' AND TABLE_SCHEMA = @schema AND TABLE_NAME = 'TableA' ORDER BY ORDINAL_POSITION FOR XML PATH('')), 1, 1, '')
        + N')
        VALUES ('
        + STUFF((SELECT ', [source].' + COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG = 'Temp' AND TABLE_SCHEMA = @schema AND TABLE_NAME = 'TableA' ORDER BY ORDINAL_POSITION FOR XML PATH('')), 1, 1, '')
        + ');';
        EXEC sp_executesql @sql;
        SELECT @sql;
        DELETE FROM #schemas WHERE SCHEMA_NAME = @schema;
END;
GO
SELECT * FROM [destination].tableA;
下面是一个运行的动态SQL脚本示例:

MERGE destination.tableA AS [target] USING (SELECT * FROM [source1].tableA) 
AS [source] (ID,Field2) ON [target].ID = [source].ID
WHEN MATCHED THEN UPDATE SET Field2 = [source].Field2 WHEN NOT MATCHED 
THEN INSERT (ID,Field2)
VALUES ( [source].ID, [source].Field2);
其最终结果是:

ID  Field1  Field2  Field3
1   dog     harold  NULL
2   NULL    cat     NULL
3   mouse   midge   NULL
我觉得哪个好


但是,我想您需要做一些更改才能使其与您的环境配合使用。我希望这能让您对如何实现这一点有一些想法?

如果您真的想使用SQL脚本来实现这一点,那么您可以使用动态SQL?也许有一个脚本可以对完整的列集进行数据插入,该脚本在另一个脚本提前添加新列后运行,沿着if not exists从sys.columns中选择1,其中object_id=object_id'dbo.TableA'和name='Field2',然后更改table dbo.TableA添加Field2 someDataType someConstraints;对于所需的每一列。@Stefan,您使用的是哪一版本的SQL?@Birel MSSQL 2018Well,那么,我认为AlwaysLearning建议是一个非常好的解决方案-它可能比尝试为每个客户构建不同的insert…select语句更简单。哇,您将所有内容都放在这里了,谢谢您=我并不特别需要合并。我可以从表名判断它是否需要更新或插入。但是,您将dynamicSQL组合在一起的方式比我预期的要优雅得多。*更多-…比。。。