【问题标题】:Update Query For ORACLE SQL DEVELOPERORACLE SQL DEVELOPER 的更新查询
【发布时间】:2021-03-31 22:09:37
【问题描述】:

我有四列

id fisrt_name last_name city
101 A B C
303 A B C
207 A B C
55 X Y Z
67 X Y Z
200 X Y Z

基本上 FN、LN 和 city 是相同的,但这些相同值的 id 不同。我想使用 oracle sql developer 将重复行的 ID 更新为相同,如下表所示。 id 可以更新为三个中的任何一个,但对于所有三个重复行,它应该变得相同。

id fisrt_name last_name city
101 A B C
101 A B C
101 A B C
55 X Y Z
55 X Y Z
55 X Y Z

我试过了

UPDATE TABLE T1 SET
T1.ID = ID
WHERE ROWID IN (SELECT ROWID FROM(
SELECT ROWID,ROW_NUMBER() OVER(PARTITION BY ID, CITY ORDER BY ADR_LINE_1) AS RN, ID, CITY 
FROM TABLE
WHERE (first_name,last_name,city) IN (first_name,last_name,city
from table 
group by first_name,last_name,city
having count(distinct id) >= 2)) WHERE RN = 1);

它会更新所需的行,但使用相同的 id 而不是我想要的。

【问题讨论】:

  • 您的查询远比它需要的复杂。您有两个(或更多?!)级别的SELECT 查询。您应该重构它以使用 CTE 和 JOIN 而不是拥有所有这些 WHERE x IN ( SELECT ... )
  • 另外,请使用比TABLE 更好的占位符名称,因为这是 SQL 中的关键字,这使得您的查询更难阅读。
  • 当然很欣赏关于那个桌子的建议,它只是参考任何桌子。但是有什么方法可以使用rownum来实现吗?
  • 左对齐 SQL 实在是太难读了,也难写……
  • @jarlh 我认为这是因为没有任何缩进,而且在第 7 行的大写锁定关闭之前,一半是大写的,这使得它难以阅读。同样构造 IN (first_name,last_name,city from table 没有任何意义 - 可能缺少 select 关键字。

标签: sql oracle sql-update


【解决方案1】:

我会选择相关子查询:

update t1 
set id = (
    select min(id) 
    from mytable t1 
    where t1.first_name = t.first_name and t1.lastname = t.lastname and t1.city = t.city
)
where id > (
    select min(id) 
    from mytable t1 
    where t1.first_name = t.first_name and t1.lastname = t.lastname and t1.city = t.city
)

此查询将利用 (firstname, lastname, city, id) 上的索引 - 尽管更新行也需要更新索引...

【讨论】:

    【解决方案2】:

    一种选择是使用MIN() Analytic Function 通过MERGE 语句重复三列(first_namelast_namecity)进行分组,例如

    MERGE INTO tab t1
    USING ( SELECT MIN(id) OVER (PARTITION BY first_name, last_name, city) AS new_id
              FROM tab t ) t2
       ON ( t1.rowid = t2.rowid )                 
     WHEN MATCHED THEN UPDATE SET t1.id = t2.new_id
    

    Demo

    【讨论】:

    • 你能解释一下这个 rowid 匹配是如何在分区上工作的
    • 不客气@Rishu Tripathi。事实上,我们通常不会在 SQL 语句中使用 rowid 值。因为,它们只是物理地址,并且会随着某些磁盘操作(例如 Move、Shrink ..具有独特的价值。
    【解决方案3】:

    这是一种方法 - 将您的表连接到聚合查询和更新的结果(按 fn、ln、city 分组,过滤掉具有单个 id 的组,并在剩余组中选择 min(id),然后使用更新)。

    设置测试用例:

    create table my_table (id, first_name, last_name, city) as
      select 101, 'A', 'B', 'C' from dual union all
      select 303, 'A', 'B', 'C' from dual union all
      select 207, 'A', 'B', 'C' from dual union all
      select  55, 'X', 'Y', 'Z' from dual union all
      select  67, 'X', 'Y', 'Z' from dual union all
      select 200, 'X', 'Y', 'Z' from dual union all
      select 333, 'D', 'F', 'G' from dual
    ;
    
    Table MY_TABLE created.
    

    更新:

    update
    ( select t.id, g.min_id
      from   my_table t
             inner join
             ( select min(id) as min_id, first_name, last_name, city
               from   my_table
               group  by first_name, last_name, city
               having min(id) != max(id)
             ) g
             using (first_name, last_name, city)
    )
    set id = min_id
    where id != min_id
    ;
    
    4 rows updated.
    

    检查结果:

    select * from my_table;
    
            ID FIRST_NAME LAST_NAME  CITY      
    ---------- ---------- ---------- ----------
           101 A          B          C         
           101 A          B          C         
           101 A          B          C         
            55 X          Y          Z         
            55 X          Y          Z         
            55 X          Y          Z         
           333 D          F          G   
    

    注意:如果 ID 可能为 null,则需要进行一些额外的处理(但是,列 应该 NOT NULL....是吗?)

    【讨论】:

    • Id 不为空,但其他列对于某些 id 为空
    猜你喜欢
    • 2013-06-20
    • 2021-04-12
    • 1970-01-01
    • 2012-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    相关资源
    最近更新 更多