SQL Server,更新替换旧项目的新项目的项目数量

时间:2018-04-29 01:58:52

标签: sql sql-server

我有一个带有两列OldItem和NewItem的CSV;每列包含一个整数列表。注意 - CSV将容纳大约1,000行。

OldItem | NewItem
-----------------
1021669 | 1167467
1021680 | 1167468
1021712 | 1167466
1049043 | 1000062

我们在系统中有旧项目被新项目替换,我们希望捕获第一个OldItem的当前数量并将其分配给第一个NewItem,第二个OldItem的数量分配给第三个OldItem的数量,等

问题的另一个有趣的部分是电子表格中的项目编号与与数量相关联的项目编号不匹配,系统中有一个名为Alias的转换表。

以下是我们正在与之交互的表格和列: 表Alias(本质上是一个转换表) 列别名(电子表格中的数字) 列ItemID(表中包含数量的“项目”中的数字)

表项目(包含所有项目,新旧) 列ItemID 列数量

我能想到这样做的唯一方法是在每个OldItem上做一个foreach,像这样,伪代码传入: foreach OldItem(选择Alias.ItemID WHERE Alias.Alias = OldItem) 然后以某种方式,因为我不知道如何返回并在SQL中使用该结果: 选择Item.Quantity,其中Item.ItemID = Alias.ItemID。 此时我有我想要的数量,现在我必须引用回CSV,找到与OldItem关联的NewItem,并使用NewItem重新执行此操作,然后将NewItem数量更新为我从OldItem。

-dizzy -

请帮助,我可以通过在PowerShell中包装SQL来处理逻辑位来解决这个问题,但是它会产生严重的性能影响,而且我必须在非常糟糕的网络连接的远程MANY数据库上执行此操作!

1 个答案:

答案 0 :(得分:1)

鉴于您遇到连接问题,我建议如下:

  1. 在数据库中创建工作表
  2. 将CSV导入工作表
  3. 运行将别名和数量复制到工作表中的脚本。不是必需的,但有助于审核
  4. 运行验证数据的脚本
  5. 运行将所需数据复制到Items
  6. 的脚本

    值得注意的是,这假设旧项目是唯一的,并且只会映射到一个新项目。在“测试”部分进行了检查。那个

    创建工作表

    打开SQL Server Management Studio并在数据库中运行此脚本(在下拉列表中选择它)

     -- Create a schema to hold working tables that aren't required by the application
     CREATE SCHEMA adm;
    
    -- Now create a table in this schema
    IF EXISTS (SELECT * FROM sys.objects WHERE name = 'ItemTransfer' 
               AND type = 'U' 
               AND schema_id = SCHEMA_ID('adm'))
        DROP TABLE adm.ItemTransfer;
    
    CREATE TABLE adm.ItemTransfer (
        OldItem INT NOT NULL, 
        NewItem INT NOT NULL,
        OldAlias VARCHAR(50) NULL,
        NewAlias VARCHAR(50) NULL,
        OldQuantity NUMERIC(19,2) NULL
       );
    

    导入CSV数据

    有很多方法可以做到这一点。您的约束是您不可靠的网络,以及您对不熟悉的工具进行故障排除的难易程度。这是一种可以重新运行而不会导致重复的方法:

    在Excel中打开您的CSV并将此怪物粘贴到第3行第2行:

    ="INSERT INTO adm.ItemTransfer (OldItem, NewItem) SELECT " & A2 & "," & B2 & " WHERE NOT EXISTS (SELECT * FROM adm.ItemTransfer WHERE OldItem=" & A2 & " AND NewItem=" & B2 & ");"
    

    这将为该数据生成一个insert语句。将其向下拖动以生成所有插入语句。会有很多行看起来像这样:

    INSERT INTO adm.ItemTransfer (OldItem, NewItem) SELECT 1,2 WHERE NOT EXISTS (SELECT * FROM adm.ItemTransfer WHERE OldItem=1 AND NewItem=2);
    

    将此插入字符串复制/粘贴到SQL Server Management Studio中并运行它。它应该将所有数据插入到您的工作表中。

    我还建议您将此文件保存到.SQL文件中。只有在记录不存在的情况下才会插入此插入语句,因此可以重新运行。

    注意:将数据导入SQL Server的方法有很多种。下一个最简单的方法是右键单击数据库/任务/导入平面文件,但停止重复/重新启动导入更复杂

    现在您可以运行SELECT * FROM adm.ItemTransfer,您应该会看到所有记录

    地图别名和数量

    这一步实际上可以即时完成,但我们可以将它们写入工作表,因为它可以让我们在事后进行审核

    这两个脚本将别名复制到工作表中:

    UPDATE adm.ItemTransfer
    SET OldAlias = SRC.Alias
    FROM 
    adm.ItemTransfer TGT
    INNER JOIN
    Alias SRC
    ON TGT.OldItem = SRC.ItemID;
    
    
    UPDATE adm.ItemTransfer
    SET NewAlias = SRC.Alias
    FROM 
    adm.ItemTransfer TGT
    INNER JOIN
    Alias SRC
    ON TGT.NewItem = SRC.ItemID;
    

    这个复制旧项目数量

    UPDATE adm.ItemTransfer
    SET OldQuantity = SRC.Quantity
    FROM 
    adm.ItemTransfer TGT
    INNER JOIN
    Items SRC
    ON TGT.OldAlias = SRC.ItemID;    
    

    完成这些步骤后,再次运行select语句进行检查。

    预更新检查

    在实际进行更新之前,您应该检查数据一致性

    临时表中的记录数:

    SELECT 
    COUNT(*) AS TableCount,
    COUNT(DISTINCT OldAlias) UniqueOldAlias,
    COUNT(DISTINCT NewAlias) UniqueNewAlias,
    FROM adm.ItemTransfer
    

    数字应该都相同,并且应与CSV记录计数相匹配。如果没有,则因为您缺少记录或者您没有一对一地映射

    而遇到问题

    此选项显示缺少别名的旧项目:

    SELECT * FROM adm.ItemTransfer WHERE OldAlias IS NULL
    

    此选项显示缺少别名的新项目:

    SELECT * FROM adm.ItemTransfer WHERE NewAlias IS NULL
    

    此选项显示项目表中缺少旧项目

    SELECT * 
    FROM adm.ItemTransfer T
    WHERE NOT EXISTS (
       SELECT * FROM Items I WHERE I.ItemID = T.OldItem)
    

    此选项显示项目表中缺少的新项目

    SELECT * 
    FROM adm.ItemTransfer T
    WHERE NOT EXISTS (
       SELECT * FROM Items I WHERE I.ItemID = T.NewItem)
    

    备份表并执行更新

    首先在数据库中备份表,如下所示:

    SELECT *
    INTO adm.Items_<dateandtime>
    FROM Items
    

    此脚本在您更新之前会生成Items表的副本。如果您愿意,可以稍后删除

    实际更新非常简单,因为我们事先在工作表中完成了所有工作:

    更新项目 SET Quantity = SRC.OldQuantity 来自物品TGT 内部联接 adm.ItemTransfer SRC ON SRC.NewAlias = TGT.ItemID;

    摘要

    所有这些都可以捆绑到一个脚本中,并在需要时自动化。您应该将所有工作文件保存到SQL文件,以及SELECT测试语句的输出