【问题标题】:SQL Server, updating item quantities of new items that are replacing old itemsSQL Server,更新替换旧项目的新项目的项目数量
【发布时间】:2018-04-30 11:00:56
【问题描述】:

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

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

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

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

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

table Items(这包含所有新旧项目) 列项目 ID 列数量

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

-头晕-

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

【问题讨论】:

  • 我建议将 CSV 导入工作表(现在使用 BCP 或 SSIS 甚至 SSMS 都可以),然后使用 T-SQL 来完成您的工作。 T-SQL 在集合操作方面要快得多,尤其是对于较大的集合。但是我有T-SQL背景所以我有偏见
  • 这是一次性任务还是每次更换一组新项目时都需要重复执行?
  • @Nick.McDermaid 我实际上并不知道不同 SQL 语言之间有什么区别,但是我仅限于默认情况下可以针对 MS SQL 数据库运行的任何内容,这都与 MS 有关RMS 数据库。不幸的是,我认为您的评论假设 SQL 知识水平比我高得多,因为这是我第一次编写 SQL。
  • @FDavidov 从理论上讲,这是每个数据库的一次任务,它必须在其各自数据库上的许多商店中完成,但无论如何这将是每个商店的一次任务。这种事情很多年都不会再发生了,到那时我们甚至都没有 RMS。
  • T-SQL 只是 SQL Server 的 SQL 语言。为您编写一些脚本来执行此操作可能非常简单,但您应该对这个过程感到满意。它肯定会解决糟糕的网络连接问题,因为网络流量非常少 - 所有处理都发生在站点的数据库中。新的项目记录已经存在于项目表中还是需要创建?

标签: sql sql-server


【解决方案1】:

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

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

请务必注意,这假定旧项目是唯一的,并且只会映射到一个新项目。在“测试部分”中有一个检查

创建工作表

打开 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 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 数量 = SRC.OldQuantity 来自项目 TGT 内部联接 adm.ItemTransfer SRC ON SRC.NewAlias = TGT.ItemID;

总结

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

【讨论】:

    猜你喜欢
    • 2019-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    • 2014-04-12
    • 2021-10-09
    • 1970-01-01
    相关资源
    最近更新 更多