【发布时间】:2016-11-07 05:49:25
【问题描述】:
我有一个大的(500 万行,300+ 列)csv 文件,我需要导入到 SQL Server 中的临时表中,然后运行脚本来拆分每一行并将数据插入到规范化数据库中的相关表中.源表的格式如下所示:
(fName, lName, licenseNumber1, licenseIssuer1, licenseNumber2, licenseIssuer2..., specialtyName1, specialtyState1, specialtyName2, specialtyState2..., identifier1, identifier2...)
有 50 个 licenseNumber/licenseIssuer 列、15 个 specialtyName/specialtyState 列和 15 个 identifier 列。其中至少有一个,但剩余的 49 或 14 个可能是 null。第一个标识符是唯一的,但不用作我们架构中 Person 的主键。
我的数据库架构如下所示
People(ID int Identity(1,1))
Names(ID int, personID int, lName varchar, fName varchar)
Licenses(ID int, personID int, number varchar, issuer varchar)
Specialties(ID int, personID int, name varchar, state varchar)
Identifiers(ID int, personID int, value)
在从 csv 添加新的之前,数据库中已经填充了一些 People。
解决这个问题的最佳方法是什么?
我曾尝试使用select top 1 一次一行地遍历暂存表:
WHILE EXISTS (Select top 1 * from staging)
BEGIN
INSERT INTO People Default Values
SET @LastInsertedID = SCOPE_IDENTITY() -- might use the output clause to get this instead
INSERT INTO Names (personID, lName, fName)
SELECT top 1 @LastInsertedID, lName, fName from staging
INSERT INTO Licenses(personID, number, issuer)
SELECT top 1 @LastInsertedID, licenseNumber1, licenseIssuer1 from staging
IF (select top 1 licenseNumber2 from staging) is not null
BEGIN
INSERT INTO Licenses(personID, number, issuer)
SELECT top 1 @LastInsertedID, licenseNumber2, licenseIssuer2 from staging
END
-- Repeat the above 49 times, etc...
DELETE top 1 from staging
END
这种方法的一个问题是速度太慢了,所以我将它重构为使用游标。这很有效,而且速度明显更快,但让我为Fetch INTO 声明了 300 多个变量。
是否有一种基于集合的方法可以在这里工作?这将是可取的,因为我知道游标不受欢迎,但我不确定如何将身份从INSERT 获取到People 表中,以便在其他表中用作外键而不逐行- 暂存表中的行。
另外,我怎样才能避免将插入内容复制并粘贴到许可证表中?使用光标方法我可以尝试:
FETCH INTO ...@LicenseNumber1, @LicenseIssuer1, @LicenseNumber2, @LicenseIssuer2...
INSERT INTO #LicenseTemp (number, issuer) Values
(@LicenseNumber1, @LicenseIssuer1),
(@LicenseNumber2, @LicenseIssuer2),
... Repeat 48 more times...
.
.
.
INSERT INTO Licenses(personID, number, issuer)
SELECT @LastInsertedID, number, issuer
FROM #LicenseTEMP
WHERE number is not null
不过,那里似乎仍有一些多余的复制和粘贴。
为了总结问题,我正在寻找惯用的方法来:
- 将一个大型临时表分解为一组规范化表,从一个表中检索主键/标识并将其用作其他表中的外键
- 将多行插入到来自暂存表中许多重复列的规范化表中,使用较少的样板/复制和粘贴(上面的许可证和专业)
没有谨慎的答案,我也很乐意提供可以帮助我弄清楚这一点的资源和参考资料。
【问题讨论】:
-
可以修改csv文件吗?
-
修改 csv 文件可能不切实际(在 excel 中打开它是不可能的,并且在文本编辑器中检查和编辑很难看),但是可以修改暂存表。
-
有什么可以提供
fname/lname的唯一性吗? -
@MikeNitchie,不,您只需要读取每条记录一次,然后调用构建许可证、专业和标识符的过程。但是 500 万条记录已经很多了。我认为标记每条记录是个好主意,以避免重复所有过程。
-
我同意@mcNets:在游标和逐行逻辑上进行集合操作。您应该努力为每个目标访问一次临时表(即 5 次)。
标签: sql sql-server database tsql