2017-03-04 63 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