2017-03-04 85 views
1

0匹配的所有行我有两个表:更新一个表中谁拥有1场,超过1场,或在其他表

 
CREATE TABLE huge (
    id INT PRIMARY KEY, 
    name VARCHAR2(100), 
    day INT, 
    errno INT, 
    error_message VARCHAR2(100) 
); 

CREATE TABLE smallish (
    id INT PRIMARY KEY, 
    name VARCHAR2(100), 
    day int 
); 

-- Note the lack of a foreign key between huge and smallish on name 
-- This is intentional 

我想要做的三件事情:

  1. 更新huge中的所有行,将day设置为smallish中的行,其中huge中的行恰好有一个name,位于smallish中。
  2. 更新在huge所有行有1一个errno:name not in smallisherror_message其中huge行不smallish有一个名字。
  3. 更新在huge所有行有2一个errno:name has multiple rows in smallisherror_message其中huge行有一个以上的namesmallish

我用下面的DML的这似乎工作,但其中两个在输出中给出了全表扫描,否则看起来不直观。

此外,在一个声明中完成这一切将是非常酷的,而不是三次。

更新:

以下似乎工作,看起来有点直观,但解释计划显示了巨大的全表扫描:

 
UPDATE huge h_out 
SET (day, errno, error_message) = (
    select CASE WHEN DAY IS NOT NULL AND count = 1 THEN day ELSE NULL END as bill_day, 
      CASE WHEN day IS NULL THEN 1 WHEN count > 1 THEN 2 ELSE NULL END AS errno, 
      CASE WHEN day IS NULL THEN name || ' not in smallish' WHEN count > 1 THEN name || ' has multiple rows in smallish' ELSE NULL END as error_message 
    FROM (
     select dhuge.name, max(smallish.day) as day, count(dhuge.name) as count 
     from (select distinct huge.name from huge) dhuge left join smallish on dhuge.name = smallish.name 
     group by dhuge.name 
    ) h_in 
    WHERE h_out.name = h_in.name 
); 

原文:

 
-- Problem #1 
UPDATE huge h 
SET (day) = (
    SELECT MIN(day) 
    FROM smallish s 
    WHERE h.name = s.name 
    GROUP BY s.name 
    HAVING count(1) = 1 
) WHERE EXISTS (
    SELECT null 
    FROM smallish s 
    WHERE s.name = h.name 
); 

-- Problem #2 Explain plan shows a full table scan on huge 
UPDATE huge h_out 
SET (errno, error_message) = (
    select 1, h_out.name || ' not in smallish' AS error_message FROM DUAL 
) WHERE NOT EXISTS (
    SELECT NULL 
    FROM smallish s 
    WHERE s.name = h_out.name 
); 


-- Problem #3 Explain plan shows a full table scan on huge 
UPDATE huge h 
SET (errno, error_message) = (
    SELECT 2, h.name || ' has multiple rows' FROM dual 
) WHERE EXISTS (
    SELECT s.name 
    FROM smallish s 
    WHERE h.name = s.name 
    GROUP BY s.name 
    HAVING count(1) > 1 
); 



复制:

 

DROP TABLE huge; 
DROP TABLE smallish; 

CREATE TABLE huge (
    id INT PRIMARY KEY, 
    name VARCHAR2(100), 
    day INT, 
    errno INT, 
    error_message VARCHAR2(100) 
); 


CREATE TABLE smallish (
    id INT PRIMARY KEY, 
    name VARCHAR2(100), 
    day int 
); 

create index huge_name_indx ON huge (name); 
create index smallish_name_indx ON smallish (name); 

insert into huge values (1, 'good1', null, 0, null); 
insert into huge values (2, 'good1', null, 0, null); 
insert into huge values (3, 'good1', null, 0, null); 
insert into huge values (4, 'good1', null, 0, null); 
insert into huge values (5, 'good2', null, 0, null); 
insert into huge values (6, 'good2', null, 0, null); 
insert into huge values (7, 'good2', null, 0, null); 
insert into huge values (8, 'good2', null, 0, null); 
insert into huge values (9, 'double1', null, 0, null); 
insert into huge values (10, 'double1', null, 0, null); 
insert into huge values (11, 'double1', null, 0, null); 
insert into huge values (12, 'double1', null, 0, null); 
insert into huge values (13, 'double2', null, 0, null); 
insert into huge values (14, 'double2', null, 0, null); 
insert into huge values (15, 'double2', null, 0, null); 
insert into huge values (16, 'double2', null, 0, null); 
insert into huge values(17, 'notin1', null, 0, null); 
insert into huge values(18, 'notin1', null, 0, null); 
insert into huge values(19, 'notin1', null, 0, null); 
insert into huge values(20, 'notin1', null, 0, null); 
insert into huge values(21, 'notin2', null, 0, null); 
insert into huge values(22, 'notin2', null, 0, null); 
insert into huge values(23, 'notin2', null, 0, null); 
insert into huge values(24, 'notin2', null, 0, null); 

insert into smallish values (1, 'good1', 1); 
insert into smallish values (2, 'good2', 2); 
insert into smallish values (3, 'double1', 3); 
insert into smallish values (4, 'double1', 4); 
insert into smallish values (5, 'double2', 5); 
insert into smallish values (6, 'double2', 6); 

commit; 

回答

2

要做到这一切在一个声明中,你可以使用merge

merge into huge h 
    using (select name, count(*) as cnt, max(day) as day 
      from smallish 
      group by name 
     ) s 
    on h.name = s.name 
when matched then update 
    set day = (case when s.cnt = 1 then s.day else h.day end), 
     errno = (case when s.cnt > 1 then 2 else h.errno end), 
     error_message = (case when s.cnt > 1 then s.name || ' has multiple rows in smallish' else error_message end) 
when not matched then update 
    set errno = 1, 
     error_message = h.name || ' not in smallish'; 
+0

在Oracle中,这似乎是给因为使用'update'的错误两次。蟾蜍说'发现'更新'期待'插入'。有任何想法吗? –

+0

我想你打算在括号中包含'h.name - s.name',并在匹配的error_message的case语句中包含'END'。 –

+1

有多少行很大;以及有多少行正在更新? – BobC