ちょっとややこしい?SQL


デル夫  2009-01-09 02:37:14  No: 33061

delphiというよりSQL(delphi5に付属のparadox)についての質問です。

tbl_a(id, item1, item2, ..., itemN)
tbl_b(id, itemA, itemB, ..., itemZZ)

(いずれもフィールド数は動的に変わるため不定)

というテーブルを結合したいのですが、

(1)tbl_b.itemAからitemZZのいずれの値も、tbl_a.item1〜.itemNのいずれとも一致しない場合(idのみ一致)
(2)逆にいずれかと一致する場合

にのみ、tbl_a.id=tbl_b.idをキーとして結合を実施する、というのは、条件句に

tbl_b.itemA <> tbl_a.item1
and
tbl_b.itemA <> tbl_a.item2
and
tbl_b.itemA <> tbl_a.item3

と延々と記述しないといけないのでしょうか。


delphi初心者  2009-01-09 06:39:05  No: 33062

paradoxのSQLは知らないですが、inはだめですか。
これも長くはなりますが少しすっきりします。

    tbl_b.itemA not in (tbl_a.item1,tbl_a.item2,・・・tbl_a.itemN)
and tbl_b.itemB not in (tbl_a.item1,tbl_a.item2,・・・tbl_a.itemN)
and tbl_b.itemC not in (tbl_a.item1,tbl_a.item2,・・・tbl_a.itemN)
  ・
  ・
  ・
and tbl_b.itemZ not in (tbl_a.item1,tbl_a.item2,・・・tbl_a.itemN)


デル夫  2009-01-09 17:48:04  No: 33063

delphi初心者さん、ありがとうございます。

フィールドの数が実行時によって異なるので、

tbl_b.itemA not in (tbl_a.の現在の行)

的な記述ができればと思っているのですが、無理でしょうかね。


あれ?  2009-01-09 19:41:10  No: 33064

> (1)tbl_b.itemAからitemZZのいずれの値も、tbl_a.item1〜.itemNのいずれとも一致しない場合(idのみ一致)
> (2)逆にいずれかと一致する場合
> にのみ、tbl_a.id=tbl_b.idをキーとして結合を実施する

(1)と(2)のどちらかに一致した場合って結局全部ってことになりません?
なんか考え方おかしいかな・・・


HOta  2009-01-09 19:42:51  No: 33065

項目毎に比較しているのに、肝心の項目数が不定では、無理でしょうね。
テーブルの構造を検討した方が良いと思います。


デル夫  2009-01-09 21:45:36  No: 33066

あれ?  さん、(1)と(2)は別々の作業です。書き方が悪くてすみません。

HOtaさん  項目数が一定ならばできるということでしょうか。
実は、別のソフトが吐き出すクロス集計の結果に対しての作業ですので、吐き出し側を何とかすればいいかもしれません。


beagle  2009-01-15 06:48:12  No: 33067

もう解決したでしょうか?
※paradoxは、あまり使わないし、質問者の言う「テーブルを結合」も何を
言いたいのか分かりませんが・・・
質問者は以下について情報を追加されたい。
1)tbl_a(id, item1, item2, ..., itemN)
    tbl_b(id, itemA, itemB, ..., itemZZ)
ここで  tbl_a、tbl_bでid以外の全フィールドの属性は同じなのか?
(文字と数字が混在してたりしないか?)
2)仮に、
    tbl_a(id, item1, item2,item3)
    tbl_b(id, itemA, itemB)
のようにフィールド数が分かっている場合は、条件句に
delphi初心者さん 2009/01/08(木) 21:39:05
の方法を記述すれば、望んだ結果が得られるのか?

回答をいただければ、解決策を提示できるかもしれません。
フィールド数が固定か可変かは、問題ではないと思います。


デル夫  2009-01-15 07:38:24  No: 33068

beagleさん、補足させていただきます。
結合は、文字通り、IDをキーにしたjoin操作です。たとえば(1)の場合ですと、tbl_aにもtbl_bにもid以外重複した内容のフィールドが全くない場合、tbl_cとして(id, item1, item2, ..., itemN, ..., itemA, itemB, ..., itemZZ)を生成したい、ということです。
フィールドの属性は同じvarcharです。
in()句にフィールド名を記述するとエラーになります。例えば、select 〜 where tbl_b.itemA not in (var1, var2 ... )とリテラルで展開したら正常に動作しますが、not in (tbl_a.item1, tbl_a.item2 ... )のようにフィールドを記述するとエラーになります。
とりあえず、現在は出力側ソフトのフォーマットを見直している最中です。

よろしくお願いします。


beagle  2009-01-15 17:28:09  No: 33069

>not in (tbl_a.item1, tbl_a.item2 ... )のようにフィールドを記述するとエラー
そうでしたか。ではもう一つ教えてください。
tbl_b.itemA <> tbl_a.item1 and tbl_b.itemA <> tbl_a.item2 
(中略)
and tbl_b.itemA <> tbl_a.itemN
(中略)
tbl_b.itemZZ <> tbl_a.item1 and tbl_b.itemA <> tbl_a.item2 
(中略)
and tbl_b.itemZZ <> tbl_a.itemN
という記述を自動的に生成できれば、問題は解決しますか?


デル夫  2009-01-15 18:08:39  No: 33070

beagleさん

記述の自動生成の件ですが、フィールド名にはある程度の規則性がありますので、現在の方向としては「item*が存在しているならば比較を実施」のようにSQLに文を追加していく事はできないか、というのも検討中です。

それができれば問題は解決だと思います。


beagle  2009-01-21 16:00:37  No: 33071

返答が遅れてすみません。

with  query1  do
begin
  sql.clear;
  sql.add('select * from  tbl_a ');
  open;
  for i := 0 to  FieldCount-1 do 
  begin
    Listbox1.items.add(Fields[i].FieldName); 
  end; 
end; 

そちらの環境で、この手順でフィールド名が取得できますか?
よければ、たとえば以下のやり方が考えられます。
const
  iStartField = 1;
var
 tbl_aFNArray, tbl_bFNArray : array of string;
 tbl_aFC, tbl_bFC: Integer;
 SQLText, wkaText, wkbText : string;

//tbl_aのフィールド名を取得
with  query1  do
begin
  sql.clear;
  sql.add('select * from  tbl_a ');
  open;
  tbl_aFC := FieldCount-1;
  SetLength(tbl_aFNArray, tbl_aFC);
  for i := 0 to  tbl_aFC do 
  begin
    tbl_aFNArray[i]  := Fields[i].FieldName; 
  end; 
  close;
end; 
//tbl_bのフィールド名を取得
with  query1  do
begin
  sql.clear;
  sql.add('select * from  tbl_b ');
  open;
  tbl_bFC := FieldCount-1;
  SetLength(tbl_bFNArray, tbl_bFC);
  for i := 0 to  tbl_bFC do 
  begin
    tbl_bFNArray[i]  := Fields[i].FieldName; 
  end; 
  close;
end; 
//sql文を動的作成
SQLText := '';
for i := iStartField to  tbl_aFC do //ゼロからじゃない
begin
    wkaText  := 'tbl_a.' + tbl_aFNArray[i];
    for x := iStartField to  tbl_bFC do  //ゼロからじゃない
    begin
      wkbText ;= 'tbl_b.' + tbl_bFNArray[x];
      SQLText := SQLText + wkaText + '<>' + wkbText ;
      if (i <> tbl_aFC) or (x <> tbl_bFC) then
      begin
        SQLText := SQLText + 'and';//最後の最後以外は’AND’を付ける。
      end;
    end; 
end; 
Memo1.Text := SQLText;//確認

そのままコピペで動くコードを提示したかったのですが、Delphi環境がないので、
タイプミス等あったらすみません。
※  ループの開始(ゼロか1か)と終了(FieldCountかFieldCount-1か)が正しく
    ないかもしれません。お仕事だと思うので、十分な確認をお願いします。
この投稿がお役に立てば幸いです。


デル夫  2009-02-16 06:53:00  No: 33072

諸々の事情で返答が遅くなりましたが、皆さん色々とご丁寧にありがとうございました。

beagleさん、力作のコードを提示いただき、ありがとうございました。
訳あって、まだ検証ができておりませんが、近い将来、きっと検証結果についてお知らせいたしますので、もう少しお待ち下さい。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加