Oracle SQL中两个表之间同时进行SYNC和UPDATE

时间:2014-10-13 05:33:42

标签: sql oracle

我在ORACLE SQL操作上遇到了麻烦。 首先,我有两张桌子,

TEST_TABLE_A
Insert into TEST_TABLE_A (NAME, VAL1, VAL2, STATUS) Values ('HEAD1', 100, 200, 'ACTIVE');
Insert into TEST_TABLE_A (NAME, VAL1, VAL2, STATUS) Values ('HEAD2', 300, 400, 'ACTIVE');
Insert into TEST_TABLE_A (NAME, VAL1, VAL2, STATUS) Values ('HEAD3', 500, 600, 'ACTIVE');
Insert into TEST_TABLE_A (NAME, VAL1, VAL2, STATUS) Values ('HEAD4', 700, 800, 'ACTIVE');

TEST_TABLE_B
Insert into TEST_TABLE_B (NAME, VAL1, VAL2) Values ('HEAD1', 1, 2);
Insert into TEST_TABLE_B (NAME, VAL1, VAL2) Values ('HEAD4', 700, 800);
Insert into TEST_TABLE_B (NAME, VAL1, VAL2) Values ('HEAD5', 900, 1000);

我的作业如下, 1.将表b中的数据同步到表a 2.当找到具有相同值的相同名称时,则忽略 3.当使用不同的值找到相同的名称时,将数据插入到表A中,并使用相同的名称从B中获取值,并使用' INACTIVE'更新旧行。状态 4.如果表A中没有基于表B的数据,则将数据插入表A

我的查询是这样的,

    MERGE INTO TEST_TABLE_A TGT
    USING TEST_TABLE_B SRC
        ON (TGT.NAME = SRC.NAME)

    WHEN MATCHED THEN 
        UPDATE SET TGT.VAL1 = SRC.VAL1,
               TGT.VAL2 = SRC.VAL2

    WHEN NOT MATCHED THEN
        INSERT (TGT.NAME, TGT.VAL1, TGT.VAL2, TGT.STATUS)
        VALUES (SRC.NAME, SRC.VAL1, SRC.VAL2, 'ACTIVE');

所以我面临的问题是我不能让#3工作。我尝试了很多SQL的组合,它只是没有碰巧工作。

如何通过忽略两个表中具有相同值的相同名称来使数字2工作?

我希望结果会像这样

TEST_TABLE_A
NAME   VAL1   VAL2   STATUS
-----------------------------
HEAD1  100    200    INACTIVE
HEAD1  1      2      ACTIVE
HEAD2  300    400    INACTIVE
HEAD3  500    600    INACTIVE
HEAD4  700    800    ACTIVE
HEAD5  900    1000   ACTIVE

我真的很感谢你们的帮助。 问候

3 个答案:

答案 0 :(得分:0)

试试这个:

如果HEAD2和HEAD3是非活动的

--> Update the data that does not exist in table BLE_B to be INACTIVE
 Update BLE_A
 Set STATUS = 'INACTIVE'
 From BLE_A a
 Left Join BLE_B b
    On b.Name = a.Name
    And b.Val1 = a.Val1
    And b.Val2 = a.Val2
 Where b.Name is Null


 --> Insert the data from BLE_B that does not exist in table BLE_A 
 --> or insert the data that different values with table BLE_A
 Insert Into BLE_A
 Select b.*, 'ACTIVE'
 From BLE_B b
 Left Join BLE_A a
    On a.Name = b.Name
    And a.Val1 = b.Val1
    And a.Val2 = b.Val2
 Where b.Name is Null

答案 1 :(得分:0)

您不能只为#3使用一个合并,因为您需要在相同的ON条件下更新和插入。

update test_table_a a set a.status = 'INACTIVE' 
where exists (select 1 from test_table_b b 
               where b.name = a.name and (b.val1 != a.val1 or b.val2 != a.val2));

merge into test_table_a a using test_table_b b on (b.val1 = a.val1 and b.val2 = a.val2)
when not matched then insert values (b.name, b.val1, b.val2, 'ACTIVE');

但我不明白为什么在你的输出中HEAD2和HEAD3处于' INACTIVE'状态。也许你还需要标记为“不活跃”。 TEST_TABLE_A中的行不存在于TEST_TABLE_B中(在这种情况下,您可以通过添加此条件来更改第一个更新:"或者不存在(从test_table_b b中选择1,其中b.name = a.name) &#34)

答案 2 :(得分:0)

  

我希望结果会像这样

TEST_TABLE_A
NAME   VAL1   VAL2   STATUS
-----------------------------
HEAD1  100    200    INACTIVE
HEAD1  1      2      ACTIVE
HEAD2  300    400    INACTIVE
HEAD3  500    600    INACTIVE
HEAD4  700    800    ACTIVE
HEAD5  900    1000   ACTIVE

好的,让我们看看如何才能满足SQL的每个规则。

1.首先,这两个表只是一个简单的UNION

2.然后,需要删除NAMEVAL1VAL2列上重复的行。因此,请使用ROW_NUMBER analytic。

3.最后,选择RANK为1的行。

SQL> SELECT name,
  2    val1,
  3    val2,
  4    status
  5  FROM
  6    (SELECT a.*,
  7      row_number() over(partition BY a.val1, a.val2 order by a.name, a.val1, a.val2) rn
  8    FROM
  9      ( SELECT name, val1, val2,'INACTIVE' status  FROM TEST_TABLE_A
 10      UNION
 11      SELECT b.*, 'ACTIVE' status FROM TEST_TABLE_B b ORDER BY 1
 12      ) A
 13    )
 14  WHERE rn = 1
 15  /

NAME                       VAL1       VAL2 STATUS
-------------------- ---------- ---------- --------
HEAD1                         1          2 ACTIVE
HEAD1                       100        200 INACTIVE
HEAD2                       300        400 INACTIVE
HEAD3                       500        600 INACTIVE
HEAD4                       700        800 ACTIVE
HEAD5                       900       1000 ACTIVE

6 rows selected.

SQL>

因此,它可以提供您想要的输出。

*更新**在OP的请求中添加测试用例

SQL> SELECT * FROM test_table_a;

NAME                       VAL1       VAL2 STATUS
-------------------- ---------- ---------- --------------------
HEAD1                       100        200 ACTIVE
HEAD2                       300        400 ACTIVE
HEAD3                       500        600 ACTIVE
HEAD4                       700        800 ACTIVE

SQL>
SQL> CREATE TABLE test_table_a_new AS
  2  SELECT name,
  3    val1,
  4    val2,
  5    status
  6  FROM
  7    (SELECT a.*,
  8      row_number() over(partition BY a.val1, a.val2 order by a.name, a.val1, a.val2) rn
  9    FROM
 10      ( SELECT name, val1, val2,'INACTIVE' status  FROM TEST_TABLE_A
 11      UNION
 12      SELECT b.*, 'ACTIVE' status FROM TEST_TABLE_B b ORDER BY 1
 13      ) A
 14    )
 15  WHERE rn = 1
 16  /

Table created.

SQL>
SQL> DROP TABLE test_table_a PURGE
  2  /

Table dropped.

SQL>
SQL> alter table test_table_a_new rename to test_table_a
  2  /

Table altered.

SQL> select * from test_table_a
  2  /

NAME                       VAL1       VAL2 STATUS
-------------------- ---------- ---------- --------
HEAD1                         1          2 ACTIVE
HEAD1                       100        200 INACTIVE
HEAD2                       300        400 INACTIVE
HEAD3                       500        600 INACTIVE
HEAD4                       700        800 ACTIVE
HEAD5                       900       1000 ACTIVE

6 rows selected.

SQL>