查询以将相同的ID分配给正在插入的行(如果它已存在于表中)

use*_*188 5 sql oracle plsql

我将客户记录插入到表中,如果已存在同名记录,我将为新插入的记录分配相同的ID.

假设表T有此记录:

ID | Name | Phone_Number | Date_Inserted
105| Sam  | 111111       | 04/03/2014
106| Rita | 222222       |04/03/2014
Run Code Online (Sandbox Code Playgroud)

我从表A中插入这个:

Name| Phone_Number
Sam | 333333
Run Code Online (Sandbox Code Playgroud)

插入后,表T应该具有:

ID | Name | Phone_Number | Date_Inserted
105| Sam  | 111111       | 04/03/2014
106| Rita | 222222       | 04/03/2014
105| Sam  | 333333       | 04/04/2014
Run Code Online (Sandbox Code Playgroud)

没有上述变化,它看起来像:

INSERT INTO T SELECT CustID.nextval,Name,Phone_Number,SYSDATE FROM A;
Run Code Online (Sandbox Code Playgroud)

我在考虑使用,

INSERT INTO T
  SELECT CASE 
           WHEN NOT EXISTS(select null from T WHERE T.Name=A.Name) THEN CustID.nextVal
           ELSE (select ID from T where T.Name=A.Name) 
         END, 
         Name,
         Phone_Number,
         SYSDATE 
   FROM A;
Run Code Online (Sandbox Code Playgroud)

但我不确定它是否会起作用,而且对性能而言似乎是多余的/坏的.如果有一种首选方式,请告诉我.

Jef*_*f N 8

如果您的架构没有一成不变,我可能会重新配置它,以便有一个"人"表和一个单独的"人员电话号码"表.通过这种设置,您可以将多个电话号码与一个人相关联,并且您不会踩踏ID,也不会创建非主键的令人困惑的辅助ID列.


Ben*_*Ben 1

将任何事物定性为“坏”都是主观的。只要结果是正确的,只有花费太长时间或使用太多系统资源时,某些事情才是“坏”的。定义“长”和“太多”。如果某些内容在可接受的时间内使用可接受数量的系统资源返回正确的结果,则无需进行更改。

但是,您可以注意许多事项(假设更改数据模型不是可接受的解决方案):

  • NAME, ID当您选择 onNAME并返回时,您将需要一个索引 on ID

  • 您的第二个相关子查询(select ID from T where T.Name=A.Name)返回多行,这将导致错误。您要么需要将结果集限制为单行,要么使用某些聚合函数。似乎最好添加一个附加条件where rownum < 2来限制结果,因为添加聚合将强制 Oracle 对具有该名称的每一行执行范围扫描,而您只需要查找它是否存在。

  • CASE声称它执行短路评估;当涉及序列时,这不一定是真的。

  • 我认为这不会影响您的 INSERT 语句,但可能值得将您的DATE_INSERTED列更改为默认值;这意味着您不需要将其添加到每个查询中,并且您不能忘记这样做:

     alter table t modify date_inserted date default sysdate;
    
    Run Code Online (Sandbox Code Playgroud)

将这些(相当小的)更改放在一起,您的查询可能如下所示:

insert into t (id, name, phone_number)
select coalesce( select id from t where name = a.name and rownum < 2
               , custid.nextval
                 )
     , name
     , phone_number
  from a
Run Code Online (Sandbox Code Playgroud)

只有您才能判断这是否可以接受。

我做了一些非常类似的事情 - 对于一个分析数据库,我必须维护一个旧的基于数据的主键。我能让它工作的唯一方法是每分钟在后台作业中运行它,使用相关子查询并显式添加对潜在行数的 rownum 限制。我知道在 INSERT 语句中保留这一点“更好”,但执行时间是不可接受的。我知道代码每分钟最多只能处理 10,000 行,但这并不重要,因为我每分钟最多只能向表中添加 5,000 行。这些数字将来可能会发生变化,并且随着表的增长,执行计划也可能会发生变化 - 当它发生时,我将处理问题,而不是尝试解决不存在的问题。

太长了;博士

每一段代码都可以,直到出现问题为止。虽然知识和经验可以帮助代码长时间保持良好状态,但如果不需要优化,请不要过早优化