通过将ROW_NUMBER与另一个表匹配来进行更新?

时间:2018-07-26 07:55:32

标签: sql oracle sql-update

这可以在SQL Server中完成(而我们可以在UPDATE语句中使用FROM子句)。但是我对Oracle SQL还是很陌生。这样的场景很简单。我有2个表(具有相同的行数)。现在,我需要通过匹配每个表的using (var writer = new StreamWriter("matriculasComDV.txt", false, Encoding.UTF8)) using (var reader = new StreamReader("matriculasSemDV.txt", Encoding.UTF8)) { string line = null; while ((line = reader.ReadLine()) != null) { int m_1 = Convert.ToInt32(line.Substring(0, 1)); //1st digit int m_2 = Convert.ToInt32(line.Substring(1, 1)); //2nd digit int m_3 = Convert.ToInt32(line.Substring(2, 1)); //3rd digit int m_4 = Convert.ToInt32(line.Substring(3, 1)); //4th digit int mult_m1 = m_1 * 5; int mult_m2 = m_2 * 4; int mult_m3 = m_3 * 3; int mult_m4 = m_4 * 2; int final_sum = mult_m1 + mult_m2 + mult_m3 + mult_m4; int rest_div = final_sum % 16; writer.WriteLine("{0} - {1:X}", line, rest_div); } } 将此表的一列更新为另一表的一列。

我已经参考了Oracle UPDATE,这看起来是最有前途的方法:

row_number

但是它抛出了错误:

  

无法修改映射到非键保留表的列

有一些涉及UPDATE的示例,但它并不完全符合我的情况,因为匹配条件不涉及基础表的任何现有列(我们需要更新的表)

2 个答案:

答案 0 :(得分:2)

理想情况下,表应该具有主键唯一键以便标识行。而且,如果认为两个表相关,则应该有一个相互链接的外键或一个唯一标识记录的公用列集。如果不是,则违反了RDBMS的基本原则。 row_number()是一个函数,它生成数字而不是表中存在的物理键。您应该考虑更改设计,以利用有效的数据提取方法和更简单的查询。

作为解决方法,您可以使用MERGE来使用ROWID语句。但是,请注意,如果行数不匹配或我无法想到的其他情况,则可能无法按预期工作。

MERGE INTO a 
using (SELECT a.a1, 
              b.b1, 
              a.rid 
       FROM   (SELECT a.*, 
                      row_number() 
                        OVER ( 
                          ORDER BY a1 ) AS rn, 
                      a.rowid           AS rid 
               FROM   a) a 
              JOIN (SELECT b.*, 
                           row_number() 
                             OVER ( 
                               ORDER BY b1 ) AS rn 
                    FROM   b) b 
                ON ( a.rn = b.rn )) s 
ON ( a.rowid = s.rid ) 
WHEN matched THEN 
  UPDATE SET a.a1 = s.b1; 

Demo

之所以不直接进行更新,是因为表中的行没有默认顺序。因此,拥有像主键这样的键来给我们想要的顺序至关重要。

答案 1 :(得分:1)

您可以通过语句序列实现所需的结果,但是对此没有直接的语句解决方案:

解决方案1:更改表

--alter table to add a column for sequencing
alter table A
add(rownumber number);
alter table B
add(rownumber number);

--add sequencing
update A
set rownumber = rownum;
update B
set rownumber = rownum;

--update Data
update A
set A1 = (select B1 from B where A.rownumber = B.rownumber)

--undo DDL changes
alter table A
drop column rownumber;
alter table B
drop column rownumber;


解决方案2:使用第三张表

CREATE global TEMPORARY TABLE ab 
  ( 
     a1 VARCHAR(10), 
     b1 VARCHAR(10) 
  ) 
ON COMMIT DELETE ROWS; 

INSERT INTO ab 
(SELECT a1, 
        b1 
 FROM   (SELECT a1, 
                Row_number() 
                  over ( 
                    ORDER BY a1) AS rna 
         FROM   a) xa 
        join (SELECT b1, 
                     Row_number() 
                       over ( 
                         ORDER BY b1) AS rnb 
              FROM   b) xb 
          ON xa.rna = xb.rnb); 

UPDATE a 
SET    a1 = (SELECT b1 
             FROM   ab 
             WHERE  ab.a1 = a.a1); 

DROP TABLE ab; 

如果您的row_number列与要更新的列不同,则使用Oracle Merge是一种可能的解决方案,因为合并不支持更新用于ON子句的同一列。

相关问题