- PR -

SQLで教えてください

1
投稿者投稿内容
インスパ
大ベテラン
会議室デビュー日: 2002/08/30
投稿数: 125
投稿日時: 2008-05-16 00:44
SQLでわからない事があるので、皆さんお知恵をお貸しください。
2つのテーブルがあります、TABLE_AとTABLE_B、それぞれkey1,key2,key3,seqが主キーです。

TABLE_A
key1,key2,key3,seq,countA
AAAAA,BB,CC,1,11
AAAAA,BB,CC,2,22
AAAAA,BB,CC,3,33
DDDDD,EE,FF,1,44
DDDDD,EE,FF,2,55
DDDDD,EE,FF,3,66
DDDDD,EE,FF,4,77


TABLE_B
key1,key2,key3,seq,countB
AAAAA,BB,CC,1
AAAAA,BB,CC,2
AAAAA,BB,CC,3
AAAAA,BB,CC,4
AAAAA,BB,CC,5
AAAAA,BB,CC,6
DDDDD,EE,FF,1
DDDDD,EE,FF,2

で、TABLE_BのcountBの項目をTABLE_Aから更新したいのですが、以下のような条件があります
TABALE_Bで更新する行は、key1,key2,key3が同じ値でseqが一番大きいレコードのみ1行
countBに更新する値は、TABLE_Aで同じキー(key1,key2,key3)でseqが一番大きいレコードのcountAの値
以下が更新後のTABLE_Bの形です。

TABLE_B
key1,key2,key3,seq,countB
AAAAA,BB,CC,1
AAAAA,BB,CC,2
AAAAA,BB,CC,3
AAAAA,BB,CC,4
AAAAA,BB,CC,5
AAAAA,BB,CC,6,33
DDDDD,EE,FF,1
DDDDD,EE,FF,2,77

この様なことをするUPDATE文を考えているのですが、なかなか思いつきません...
わかる方がいらっしゃれば、お教え願えないでしょうか。
よろしくお願いいたします。
忠犬
大ベテラン
会議室デビュー日: 2006/05/01
投稿数: 109
投稿日時: 2008-05-16 01:02
RDBMS名とバージョンを明記してください。
未記入
会議室デビュー日: 2006/11/10
投稿数: 12
投稿日時: 2008-05-16 10:16
oracle前提
ちっと脳内だけでやったので
きちっと検証してね

コード:
update TABLE_B b
set b.countB = (
        select countA from TABLEA d
        where   d.key1 = b.key1 and
                d.key2 = b.key2 and
                d.key3 = b.key3 and
                d.seq >= all (
                        select e.seq from TABLE_A e
                        where   e.key1 = d.key1 and
                                e.key2 = d.key2 and
                                e.key3 = e.key3
                        )
    )
where exists(
    select * from TABLE_B a
    where   a.key1 = b.key1 and
            a.key2 = b.key2 and
            a.key3 = b.key3 and
            a.seq >= all (
                    select c.seq from TABLE_B c
                    where   c.key1 = a.key1 and
                            c.key2 = a.key2 and
                            c.key3 = a.key3
                    )
    )


明智重蔵
大ベテラン
会議室デビュー日: 2005/09/05
投稿数: 127
投稿日時: 2008-05-16 19:53
Oracle10gで作ってみました。

コード:
create table TABLE_A (key1,key2,key3,seq,countA) as
select 'AAAAA','BB','CC',1,11 from dual union
select 'AAAAA','BB','CC',2,22 from dual union
select 'AAAAA','BB','CC',3,33 from dual union
select 'DDDDD','EE','FF',1,44 from dual union
select 'DDDDD','EE','FF',2,55 from dual union
select 'DDDDD','EE','FF',3,66 from dual union
select 'DDDDD','EE','FF',4,77 from dual;

alter table TABLE_A add primary key(key1,key2,key3,seq);

create table TABLE_B (key1,key2,key3,seq,countB) as
select 'AAAAA','BB','CC',1,999 from dual union
select 'AAAAA','BB','CC',2,999 from dual union
select 'AAAAA','BB','CC',3,999 from dual union
select 'AAAAA','BB','CC',4,999 from dual union
select 'AAAAA','BB','CC',5,999 from dual union
select 'AAAAA','BB','CC',6,999 from dual union
select 'DDDDD','EE','FF',1,999 from dual union
select 'DDDDD','EE','FF',2,999 from dual;

alter table TABLE_B add primary key(key1,key2,key3,seq);

BYPASS_UJVCヒントを使う方法(オススメしませんが)

update
(select /*+ BYPASS_UJVC */
 a.countA as NewValue,b.countB as oldValue
   from TABLE_A a join TABLE_B b
     on (a.key1 = b.key1
     and a.key2 = b.key2
     and a.key3 = b.key3)
 where a.seq = (select max(c.seq) from TABLE_A c
                 where c.key1 = a.key1
                   and c.key2 = a.key2
                   and c.key3 = a.key3)
   and b.seq = (select max(c.seq) from TABLE_B c
                 where c.key1 = a.key1
                   and c.key2 = a.key2
                   and c.key3 = a.key3))
set oldValue = NewValue;

ベタなupdate文を使う方法

update TABLE_B b
   set countB = (select distinct
                 Last_Value(countA)
                 over(order by seq Rows between Unbounded Preceding and Unbounded Following)
                   from TABLE_A a
                  where a.key1 = b.key1
                    and a.key2 = b.key2
                    and a.key3 = b.key3)
 where seq = (select max(c.seq) from TABLE_B c
               where c.key1 = b.key1
                 and c.key2 = b.key2
                 and c.key3 = b.key3)
   and exists(select 1 from TABLE_A c
               where c.key1 = b.key1
                 and c.key2 = b.key2
                 and c.key3 = b.key3);


ノラ
常連さん
会議室デビュー日: 2003/11/06
投稿数: 37
お住まい・勤務地: 東京都
投稿日時: 2008-05-19 14:55
> 明智重蔵さんへ
記憶違いでなければ「BYPASS_UJVC」ヒントはインラインビューのSELECT句に使うのではなく、UPDATE句の後ろにつけるのではないでしょうか。
明智重蔵
大ベテラン
会議室デビュー日: 2005/09/05
投稿数: 127
投稿日時: 2008-05-19 19:17
どっちでもいいみたいですねぇ
BYPASS_UJVCヒントは、マニュアルにのってないので真相は分かりませんが・・・

コード:
update
(select /*+ BYPASS_UJVC */
 a.countA as NewValue,b.countB as oldValue
   from TABLE_A a join TABLE_B b
     on (a.key1 = b.key1
     and a.key2 = b.key2
     and a.key3 = b.key3)
 where a.seq = (select max(c.seq) from TABLE_A c
                 where c.key1 = a.key1
                   and c.key2 = a.key2
                   and c.key3 = a.key3)
   and b.seq = (select max(c.seq) from TABLE_B c
                 where c.key1 = a.key1
                   and c.key2 = a.key2
                   and c.key3 = a.key3))
set oldValue = NewValue;

update /*+ BYPASS_UJVC */
(select
 a.countA as NewValue,b.countB as oldValue
   from TABLE_A a join TABLE_B b
     on (a.key1 = b.key1
     and a.key2 = b.key2
     and a.key3 = b.key3)
 where a.seq = (select max(c.seq) from TABLE_A c
                 where c.key1 = a.key1
                   and c.key2 = a.key2
                   and c.key3 = a.key3)
   and b.seq = (select max(c.seq) from TABLE_B c
                 where c.key1 = a.key1
                   and c.key2 = a.key2
                   and c.key3 = a.key3))
set oldValue = NewValue;


ノラ
常連さん
会議室デビュー日: 2003/11/06
投稿数: 37
お住まい・勤務地: 東京都
投稿日時: 2008-05-20 18:08
そうでしたか。完全に思い込んでいました。失礼しました。
indigo-x
大ベテラン
会議室デビュー日: 2008/02/21
投稿数: 207
お住まい・勤務地: 太陽の塔近く
投稿日時: 2008-05-20 19:45
メンテナンス考えたら
ベタな感じで作ったほうがよいのでは。。。。

(まあ、勉強または作り逃げならOK。。。)
1

スキルアップ/キャリアアップ(JOB@IT)