避免从csv文件中插入表值重复项

时间:2018-07-29 22:53:35

标签: sql sql-server pyodbc

我有一个.csv文件,其中包含6亿行。我需要将其上传到数据库中。它将有3列被分配为主键。

我使用pandas读取1000行的文件。

在每次块迭代中,我都使用

INSERT INTO db_name.dbo.table_name("col1", "col2", "col3", "col4")
VALUES (?,?,?,?)

cursor.executemany(query, df.values.tolist())  

在python中使用pyodbc的语法可上传1000行数据。

不幸的是,显然存在一些重复的行。遇到重复的行时,上传将停止,并出现来自SQL Server的错误。

问题:我如何上传数据,以便每当遇到重复而不是停止重复时,都将跳过该行并上传其余内容?我在insert into table from another tableinsert into table from variables declared上发现了一些问题和答案,但是从文件中读取并使用insert into table col_names values()命令却没有发现任何问题和答案。

基于这些答案,一个想法可能是:

每次大块迭代:

  1. 上传到临时表
  2. 执行从临时表到最终表的插入
  3. 删除临时表中的行

但是,这么大的文件每秒很重要,我一直在寻找效率更高的答案。

我也尝试使用python处理重复项,但是,由于文件太大而无法容纳到内存中,所以我找不到解决方法。

问题2:如果我使用bulk insert,我将如何跳过重复项?

谢谢

4 个答案:

答案 0 :(得分:0)

您可以尝试使用CTE和INSERT ... SELECT ... WHERE NOT EXISTS

WITH cte
AS
(
SELECT ? col1,
       ? col2,
       ? col3,
       ? col4
)
INSERT INTO db_name.dbo.table_name
            (col1,
             col2,
             col3,
             col4)
            SELECT col1,
                   col2,
                   col3,
                   col4
                   FROM cte
                   WHERE NOT EXISTS (SELECT *
                                            FROM db_name.dbo.table_name
                                            WHERE table_name.col1 = cte.col1
                                                  AND table_name.col2 = cte.col2
                                                  AND table_name.col3 = cte.col3
                                                  AND table_name.col4 = cte.col4);

如果该列不是主键的一部分,则可能删除一些table_name.col<n> = cte.col<n>

答案 1 :(得分:0)

我总是总是首先加载到临时加载表中,该表在这些列上没有任何唯一性或PK约束。这样,您始终可以看到整个文件已加载,这在任何ETL工作中都是非常宝贵的检查,对于源数据的任何其他简单分析也是如此。

然后,使用前面的答案中建议的插入内容,或者,如果您知道目标表为空,则只需

INSERT INTO db_name.dbo.table_name(col1,col2,col3,col4)
SELECT distinct col1,col2,col3,col4 from load_table

答案 2 :(得分:0)

最好的方法是使用临时表并执行 MERGE-INSERT 语句。您可以执行以下操作(未经测试):

CREATE TABLE #MyTempTable (col1 VARCHAR(50), col2, col3...);

INSERT INTO #MyTempTable(col1, col2, col3, col4)
VALUES (?,?,?,?)

CREATE CLUSTERED INDEX ix_tempCol1 ON #MyTempTable (col1);

MERGE INTO db_name.dbo.table_name AS TARGET
USING #MyTempTable AS SOURCE ON TARGET.COL1 = SOURCE.COL1 AND TARGET.COL2 = SOURCE.COL2 ...
WHEN NOT MATCHED THEN
    INSERT(col1, col2, col3, col4)
    VALUES(source.col1, source.col2, source.col3, source.col4);

您需要为临时表考虑最佳索引,以使 MERGE 更快。使用未匹配时语句,可以根据 ON子句避免重复。

答案 3 :(得分:0)

SQL Server Integration Services提供了一种方法,该方法可以从源中读取数据(通过Dataflow任务),然后使用其排序控件(用于删除重复项的复选框)删除重复项。

https://www.mssqltips.com/sqlservertip/3036/removing-duplicates-rows-with-ssis-sort-transformation/

当然,必须对数据进行排序,并且6000万以上的行不会很快。


如果要使用纯SQL Server,则需要一个临时表(无pk约束)。将数据导入到暂存中之后,您将使用过滤组合PK组合的方式插入目标表。例如,

Insert into dbo.RealTable (KeyCol1, KeyCol2, KeyCol3, Col4) 
Select Col1, Col2, Col3, Col4 
  from dbo.Staging S 
 where not exists (Select *
                     from dbo.RealTable RT 
                    where RT.KeyCol1 = S.Col1
                      AND RT.KeyCol2 = S.Col2
                      AND RT.KeyCol3 = S.Col3
                  )

理论上,您还可以使用集合运算符EXCEPT,因为它从两个表中获取不同的值。例如:

INSERT INTO RealTable
SELECT * FROM Staging
EXCEPT
SELECT * FROM RealTable

将从暂存中插入不同的行到RealTable(RealTable中尚不存在)。此方法未考虑在多行上使用不同值的复合PK,因此插入错误将指示将不同的值分配给csv中的同一PK复合键。