根据两个列检查重复项


Check for duplicates based on two columns

所以我有一个员工表如下:

empid | companyid | empnum | ...
  1   |     1     |    1   | ...
  2   |     1     |    2   | ...
  3   |     1     |    3   | ...
  4   |     2     |    1   | ...
  5   |     2     |    2   | ...

表中的每个雇员条目都有一个唯一的ID (empid),该ID由MSSQL自动生成。我有一个PHP应用程序,它以一个CSV文件作为输入,其中包含员工的"主列表"。然而,CSV文件只有从"empnum"向右的列(它不包含companyid或employeeid)。在遍历CSV文件的每一行时添加companyid。CSV 应该只包含尚未在数据库中的员工,但没有保证,所以我需要在插入之前检查以确保员工不在数据库中。验证方法是确保对于这个特定的companyid(假设我们插入的是companyid = 1),表中没有匹配的空数。如果我有一个CSV文件,里面有这些数据,它将是有效的:

empnum, ...
4, ...

然而,如果我有一个CSV文件与这些数据,它将是无效的:

empnum, ...
3, ...

因为3已经作为companyid=1的空数存在,所以整个导入应该失败。在PHP应用程序中,我有:

try {
   db->beginTransaction();
   while (($data = fgetcsv($handle, 5000, ",")) !== FALSE) {
      //SQL TO INSERT ROW   
   }
   db->commit();
} catch (PDO Exception) {
   db->rollBack();
}

我应该使用什么SQL来插入行,以便如果该公司id已经存在空值,它将导致异常?我需要对数据库进行哪些更改?我最初的想法是:

选项1—插入到临时表中,然后运行select查询,根据companyid/empnum中的匹配值连接两个表,如果返回的行数> 0,则抛出异常。利:只有一个选择。缺点:所有的东西都被插入到临时表中,然后被转储到真实表中,如果它通过,select =如果失败,会浪费很多时间

Option 2-基于当前行执行select语句,如果返回的rows> 0,抛出异常,否则插入到真实表中。利:你可以在失败发生时及时发现,这样你就可以节省时间。缺点:你的查询现在增加了(2 -1),所以如果你成功了,你会有很多额外的开销!

所以我的问题是:-最佳选项是什么(1、2还是其他选项)?-我能以某种方式让MSSQL抛出异常时插入?

选项1是加载数据的'标准'方式(当然在我的世界里)。您的临时表实际上被称为"staging"表。这将比逐行检查(查找RBAR)快得多。

事实上,最耗费时间的总是一行一行地做事情。

一个泥图性能比较:

选项1:

  1. 对表逐行进行初始插入(慢)
  2. 使用单个SELECT查询(快速)捕获表之间的重复项
  3. 如果成功,将staging复制到活动表中(快速)

选项2:

  1. 从CSV中逐行加载数据(medium)
  2. 在执行此操作时,Capture通过每次选择(慢)逐行复制

不清楚的是,当你在选项2中发现重复时,你会怎么做?您是要回滚所有其他记录,还是要通知用户并继续?