【问题标题】:Avoiding duplicates during insert在插入期间避免重复
【发布时间】:2020-01-30 23:52:34
【问题描述】:

我正在研究一个存储过程,该过程当前每小时构建我们的事实表。目前,在每小时刷新期间,它会截断表并每次插入新数据。我正在尝试将其更改为仅删除不需要的行并附加新行。我已经得到了删除部分,但目前,由于 ID 列(主键)是在插入时创建的,我不确定如何避免插入重复记录,这是我目前看到的。

目前,存储过程在插入时插入主键 (ID)。我取出了截断表查询并用删除查询替换了它。现在我需要在插入过程中避免重复。

   --INSERT DATA FROM TEMP TABLE TO FACTBP
   INSERT INTO dbo.FactBP
   SELECT 
   [SOURCE]
  ,[DC_ORDER_NUMBER]
  ,[CUSTOMER_PURCHASE_ORDER_ID]
  ,[BILL_TO]
  ,[CUSTOMER_MASTER_RECORD_TYPE]
  ,[SHIP_TO]
  ,[CUSTOMER_NAME]
  ,[SALES_ORDER]
  ,[ORDER_CARRIER]
  ,[CARRIER_SERVICE_ID]
  ,[CREATE_DATE]
  ,[CREATE_TIME]
  ,[ALLOCATION_DATE]
  ,[REQUESTED_SHIP_DATE]
  ,[ADJ_REQ_SHIP]
  ,[CANCEL_DATE]
  ,[DISPATCH_DATE]
  ,[RELEASED_DATE]
  ,[RELEASED_TIME]
  ,[PRIORITY_ORDER]
  ,[SHIPPING_LOAD_NUMBER]
  ,[ORDER_HDR_STATUS]
  ,[ORDER_STATUS]
  ,[DELIVERY_NUMBER]
  ,[DCMS_ORDER_TYPE]
  ,[ORDER_TYPE]
  ,[MATERIAL]
  ,[QUALITY]
  ,[MERCHANDISE_SIZE_1]
  ,[SPECIAL_PROCESS_CODE_1]
  ,[SPECIAL_PROCESS_CODE_2]
  ,[SPECIAL_PROCESS_CODE_3]
  ,[DIVISION]
  ,[DIVISION_DESC]
  ,[ORDER_QTY]
  ,[ORDER_SELECTED_QTY]
  ,[CARTON_PARCEL_ID]
  ,[CARTON_ID]
  ,[SHIP_DATE]
  ,[SHIP_TIME]
  ,[PACKED_DATE]
  ,[PACKED_TIME]
  ,[ADJ_PACKED_DATE]
  ,[FULL_CASE_PULL_STATUS]
  ,[CARRIER_ID]
  ,[TRAILER_ID]
  ,[WAVE_NUMBER]
  ,[DISPATCH_RELEASE_PRIORITY]
  ,[CARTON_TOTE_COUNT]
  ,[PICK_PACK_METHOD]
  ,[RELEASED_QTY]
  ,[SHIP_QTY]
  ,[MERCHANDISE_STYLE]
  ,[PICK_WAREHOUSE]
  ,[PICK_AREA]
  ,[PICK_ZONE]
  ,[PICK_AISLE]
  ,EST_DEL_DATE
  ,null
  --,[ID]
  FROM #TEMP_FACT
  --code for avoiding duplicates

   --CLEAR ALL DATA FROM FACTBP
   DELETE FROM dbo.FactBP
   WHERE SHIP_DATE < DATEADD(s,-1,DATEADD(mm, 
   DATEDIFF(m,0,GETDATE())-2,0)) and SHIP_DATE IS NOT NULL

【问题讨论】:

  • 是否有任何候选键不包含ID 列?如果是这样,您可以使用它来查找重复项。
  • 定义什么是副本?此外,您真的不需要在您的删除中使用 IS NOT NULL。它是完全多余的,因为 NULL 不会小于任何计算。
  • 我会根据您用来定义副本的任何标准将表 #TEMP_FACT 加入 dbo.FactBP。然后是 where 子句where dbo.FactBP.somecolumnusedinjoin is null

标签: sql sql-server duplicates sql-insert


【解决方案1】:

您需要检查natural key。由于您在谈论事实表,因此自然键可能是许多字段的组合。如果我们假设 SOURCE 和 DC_ORDER_NUMBER 构成自然键,则应该可以:

INSERT INTO dbo.FactBP

SELECT 
  t.[SOURCE]
, t.[DC_ORDER_NUMBER]
, t.[CUSTOMER_PURCHASE_ORDER_ID]
, t.[BILL_TO]
, t.[CUSTOMER_MASTER_RECORD_TYPE]
, t.[SHIP_TO]
, t.[CUSTOMER_NAME]
, t.[SALES_ORDER]
, t.[ORDER_CARRIER]
, t.[CARRIER_SERVICE_ID]
, t.[CREATE_DATE]
, t.[CREATE_TIME]
, t.[ALLOCATION_DATE]
, t.[REQUESTED_SHIP_DATE]
, t.[ADJ_REQ_SHIP]
, t.[CANCEL_DATE]
, t.[DISPATCH_DATE]
, t.[RELEASED_DATE]
, t.[RELEASED_TIME]
, t.[PRIORITY_ORDER]
, t.[SHIPPING_LOAD_NUMBER]
, t.[ORDER_HDR_STATUS]
, t.[ORDER_STATUS]
, t.[DELIVERY_NUMBER]
, t.[DCMS_ORDER_TYPE]
, t.[ORDER_TYPE]
, t.[MATERIAL]
, t.[QUALITY]
, t.[MERCHANDISE_SIZE_1]
, t.[SPECIAL_PROCESS_CODE_1]
, t.[SPECIAL_PROCESS_CODE_2]
, t.[SPECIAL_PROCESS_CODE_3]
, t.[DIVISION]
, t.[DIVISION_DESC]
, t.[ORDER_QTY]
, t.[ORDER_SELECTED_QTY]
, t.[CARTON_PARCEL_ID]
, t.[CARTON_ID]
, t.[SHIP_DATE]
, t.[SHIP_TIME]
, t.[PACKED_DATE]
, t.[PACKED_TIME]
, t.[ADJ_PACKED_DATE]
, t.[FULL_CASE_PULL_STATUS]
, t.[CARRIER_ID]
, t.[TRAILER_ID]
, t.[WAVE_NUMBER]
, t.[DISPATCH_RELEASE_PRIORITY]
, t.[CARTON_TOTE_COUNT]
, t.[PICK_PACK_METHOD]
, t.[RELEASED_QTY]
, t.[SHIP_QTY]
, t.[MERCHANDISE_STYLE]
, t.[PICK_WAREHOUSE]
, t.[PICK_AREA]
, t.[PICK_ZONE]
, t.[PICK_AISLE]
, t.EST_DEL_DATE
, null
--,[ID]

FROM #TEMP_FACT t
  left outer join dbo.FactBP f on f.[SOURCE] = t.[SOURCE]
                              and f.[DC_ORDER_NUMBER] = t.[DC_ORDER_NUMBER]

where f.[SOURCE] is null

调整联接和WHERE 子句以匹配表的自然键。

您还应该再看看您的DELETE 脚本。您真的要删除所有带有SHIP_DATE &lt; 2019-07-31 23:59:59.000 的记录吗?还是应该是&lt;=?也许这会更好(更简单):

DELETE FROM dbo.FactBP
WHERE SHIP_DATE < cast(dateadd(day, 1, EOMONTH(getdate(), -3)) as datetime2)
  and SHIP_DATE IS NOT NULL

【讨论】:

  • 使用 where not exists 子句通常是这类事情的首选,不是吗?相同的想法,但您只需说 from #TEMP_FACT t where not exists (select 1 from dbo.FactBP f on t.[SOURCE] = f.[SOURCE] and t.[DC_ORDER_NUMBER] = f.[DC_ORDER_NUMBER]) 而不是 join,因为您不需要 factbp 的任何实际结果
  • 啊,我明白了。我会试试的。谢谢!
  • @dougp 您提供的删除语句继续抛出“System.OutOfMemoryException”,我真的不明白为什么会这样。
  • 嗨@UmairAhmed,原因是您的服务器两次将所有信息拉入内存,而不存在的查询更有效并且不会这样做。
  • @SeanBrookins 说得通。谢谢!
猜你喜欢
  • 1970-01-01
  • 2016-12-01
  • 1970-01-01
  • 2021-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多