DOBON.NET DOBON.NETプログラミング掲示板過去ログ

SQL SERVER、2つのテーブルで行の値を一致したい

環境/言語:[windows vista]
分類:[その他]

質問があるのですが、もしご存知の方がいらっしゃいましたらお教えいただけませんでしょうか?

SQL SERVERでテーブルAとテーブルBがあってそれぞれ行数は同じだとします。Aの
列とBの列に一致するものがない場合でも、Aの一行目の値はBの一行目の値、Aの二行目の値
はBの二行目の値、Aの三行目の値はBの三行目の値、といったように最終行までテーブルAと
テーブルBの値が強制的に一致するようにすることはできますでしょうか。

ALTER procedure SP_test_update
as
begin

declare @OrderID int,
@ProductID int

begin tran

declare CUR cursor
for
select
OrderID,
ProductID
from
[A]
order by
OrderID

open CUR

fetch next from CUR
into @OrderID,@ProductID

while @@FETCH_STATUS = 0
begin

update [B]
set OrderID = @OrderID,
Quantity = @ProductID



fetch NEXT from CUR
into @OrderID,@ProductID

end

close CUR
deallocate CUR

rollback tran

end

上記まで作ったあとがうまくいきません。
もし、わかる方がいらっしゃいましたら、お教え下さい。お願いします。
■No31805に返信(TKさんの記事)
> 質問があるのですが、もしご存知の方がいらっしゃいましたらお教えいただけませんでしょうか?
> 
> SQL  SERVERでテーブルAとテーブルBがあってそれぞれ行数は同じだとします。Aの
> 列とBの列に一致するものがない場合でも、Aの一行目の値はBの一行目の値、Aの二行目の値
> はBの二行目の値、Aの三行目の値はBの三行目の値、といったように最終行までテーブルAと
> テーブルBの値が強制的に一致するようにすることはできますでしょうか。
> 
お分かりの方ではないのですが勝手に書いています。

できるかとの問いなので、条件付でなら出来ると答えます。
表 B には OrdrID と Quantity 以外の列があるのかどうかはっきりしないので、
この2項目しかないのなら簡単な方法があります。
表 A でも表 B でも OrderID はユニーク(同じ値が存在しない)ですか?
または、2つの項目でならユニークなんでしょうか?
こういった条件が判らないので賢い方法は思いつきません。

あなたが提示された方法は上手くいきそうな感じがしません。
表 B を無条件で UPDATE するところが上手くいきそうに思えないのです
これでは、表 A からフェッチするたびに表 B 全体を表 A から取得したのと同じ
値に更新するように見えます。

> 上記まで作ったあとがうまくいきません。
どう上手くいかないか書いていないので、対策までは思いつきません。
しま 様

お返事いただきましてありがとうございます。

ご質問いただきました件についてなのですが、表A、表Bにはともに OrdrID と Quantity 以外の列があり、かつ OrdrID と Quantity はユニーク(同じ値が存
在しない)ではありません。カーソルでできるかなと思ったのですがうまくいか
ず、質問させていただきました。

それでは、失礼します。
■No31807に返信(TKさんの記事)
> しま 様
>
> お返事いただきましてありがとうございます。
>
> ご質問いただきました件についてなのですが、表A、表Bにはともに OrdrID と Quantity 以外の列があり、かつ OrdrID と Quantity はユニーク(同じ値が存
> 在しない)ではありません。

複数の列を組合わせても行固有の値がないと解釈します。
表 A,B それぞれで各行が区別できる行に固有な値がないのなら行固有の値の列を含む作業用の表を作るか表 A,B に行固有な値の列を作りましょう
そうすれば、行単位に更新が出来るのではないですか?

> カーソルでできるかなと思ったのですがうまくいか
> ず、質問させていただきました。
>
どう上手くいかないのですか?

あと、SQL Server だけでなく、バージョンやエディションやについても書きましょう
■No31805に返信(TKさんの記事)
> SQL SERVERでテーブルAとテーブルBがあってそれぞれ行数は同じだとします。
行数は必ず一致するのですね?

内容によっては、カーソルで一行ずつ処理するよりも、
 CREATE INSERT INTO #TemporaryTable SELECT … FROM …
等で一時表に結果を格納し、それを使って一括アップデートした方が
効率が良いかと思います。


> Aの列とBの列に一致するものがない場合でも、
>  Aの一行目の値はBの一行目の値、
>  Aの二行目の値はBの二行目の値、
>  Aの三行目の値はBの三行目の値、
> といったように最終行までテーブルAとテーブルBの値が
> 強制的に一致するようにすることはできますでしょうか。

たとえば、A 側の OrderID, ProductID が
 1行目: 11, A1
 2行目: 22, A2
 3行目: 33, A3
 4行目: 55, A4
となっていて、B 側については
 1行目: 11, B1
 2行目: 33, B2
 3行目: 44, B3
 4行目: 55, B4
だったとします。(OrderID = 33 の行番号が違っている状態です)

この場合、結果はどのようになってほしいのでしょうか?


(案1)OrderID は無視して、行番号のみでマッチさせる
 1行目: 11, B1
 2行目: 22, B2
 3行目: 33, B3
 4行目: 55, B4

(案2)行番号ではなく、OrderID のマッチングでマージする
 1行目: 11, B1
 2行目: 22, A2
 3行目: 33, B2
 4行目: 44, B3
 5行目: 55, B4

(案3)マッチングは無視して、B の値を強制的にセットする
 1行目: 11, B1
 2行目: 33, B2
 3行目: 44, B3
 4行目: 55, B4



案1 だとしたら、下記のような結果を反映させればよいと思います。

SELECT A1.OrderID, B1.ProductID FROM
  (
    SELECT
       ROW_NUMBER() OVER (ORDER BY OrderID) NUM,
       OrderID,
       ProductID
    FROM
       [A]
  ) A1
  FULL OUTER JOIN 
  (
    SELECT
       ROW_NUMBER() OVER (ORDER BY OrderID) NUM,
       OrderID,
       ProductID
    FROM
       [B]
  ) B1
  ON A1.NUM = B1.NUM
ORDER BY ISNULL(A1.OrderID, B1.OrderID)



案2 だとすれば、こんな結果。

SELECT
  ISNULL(B.OrderID, A.OrderID) OrderID
, ISNULL(B.ProductID, A.ProductID) ProductID
FROM
  A FULL OUTER JOIN B ON A.OrderID = B.OrderID
ORDER BY ISNULL(B.OrderID, A.OrderID)



案3 だとすれば、A を 全 DELETE して B を全件 INSERT するのと
同じ結果になるように見えます。OrderID, ProductID 以外の列が
ある場合には、それらをどのように扱うのか考慮する必要がありますが…。
しま 様
カーソルで実行するとおっしゃるとおり、全行更新してしまい
思い通りにいきませんでした。

魔界の仮面弁士 様
(案1)が私のやりたいことでした。お教えいただきましたとお
りに実行してみたらうまくいきました。誠にありがとうござい
ます。SQL SERVERはORACLEのように擬似行できないようですが、
このようなやり方もあるのですね。勉強になりました。

最後にお二方とも丁寧にお教えいただきましてありがとうござ
いました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板