テーブル結合によるデータ取得時の空白検索について

このQ&Aのポイント
  • テーブル結合によりデータを取得する際に、検索条件に空白を指定すると結果が少なくなる現象が起こる問題について相談です。
  • 現在、画面上の検索条件に空白を設定すると、テーブル結合により検索結果が減少する現象が発生しています。
  • テーブルAとテーブルBを結合してデータを表示していますが、空白を指定するとテーブルBにレコードがないデータが検索されないため、結果が少なく表示されます。
回答を見る
  • ベストアンサー

2つのテーブルからのレコード取得

はじめまして。 現在、画面上で検索条件を選択し、検索ボタンを押すと結果を返すアプリケーションを作成しておりますが、 画面上の検索の条件に「空白」を加えると、検索前に空白で表示されていた件数に比べて少ない結果になる、という現象が起こっています。 原因は、テーブルAとテーブルBを外部結合させてデータを取得して表示していますが、 検索前はBにレコードを持たないデータも表示しており、対象項目に検索条件「空白」を設定すると、テーブルBにレコードを持ち、 かつ該当項目が空白(null)であるデータのみ検索して、テーブルBにレコードがないデータは検索されないため、検索前より件数が少なく表示されるためだと判明しました。 画面上空白が選択されたら、テーブルAの該当項目は空白、テーブルBにはデータを持たないレコードも表示したいのですが、 どのようにすればよいかご教示いただければ有難いです。 (検索条件は複数あり、空白を指定できる項目も複数あるという前提です。) 以上、よろしくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • jamshid6
  • ベストアンサー率88% (591/669)
回答No.5

なんとなく誤解があるんだろうなぁと思っていましたが。。 LEFT OUTER JOINの結果のNULLとレコード自体のNULLには何の違いもありません。NULLはNULLです。 以下で確認してください。質問者さんの考え方では、以下でもKEYID=2のレコードが抽出されることに なりますが、実際には抽出されません。 DECLARE @TBLA TABLE ([KEYID][int],[F1][varchar](5)) DECLARE @TBLB TABLE ([KEYID][int],[F2][varchar](5)) INSERT INTO @TBLA VALUES (1,'X') INSERT INTO @TBLA VALUES (2,'Y') INSERT INTO @TBLA VALUES (3,'Z') INSERT INTO @TBLB VALUES (1,'ABC') INSERT INTO @TBLB VALUES (3,'BCD') SELECT a.KEYID,a.F1,b.F2 FROM @TBLA a LEFT OUTER JOIN @TBLB b ON b.KEYID=a.KEYID WHERE b.F2='ABC'

trillian
質問者

お礼

回答が遅くなり、申し訳ありません。 実際に試したところ、LEFT JOINのWHERE句の検索内容に沿ったデータのみ抽出されました。 私自身の混乱の原因としては (1)「*=」を使用していた際、where句の条件に「項目=Null」を入れていたところ全件ヒットしていた (2)(1)により、外部結合では、結合される側をwhere句の条件で指定しても全件ヒットしてしまうものと思ってしまった というところにあるようです。 (1)に関してはSQLserverのバージョンの問題で、曖昧な条件になってしまっているところに原因があるようですが、(2)に関しては外部結合が根本的に分かっていない(結合した後に抽出していることが理解できていない)ところに原因があるように思います。SQLをもっと勉強する必要がありますね。 この度はありがとうございました。

その他の回答 (4)

  • jamshid6
  • ベストアンサー率88% (591/669)
回答No.4

#2,#3です。 >ご提示いただいたSQLですと、検索の際、Bのnull以外の検索値を指定した場合、Bのテーブルに値を持っていないデータもヒットしてしまうかと思います。 そんなことはないですよ。 例えば、BのF4というカラムに"ABC"という条件を指定すると、条件にはb.F4='ABC'が追加されます。 ということはBに値のない(NULLの)レコードはヒットしないです。 一方、BのF4というカラムに""(空白)という条件を指定すると、条件には(b.F4='' OR b.F4 IS NULL)が追加されます。 したがって、この場合はBに値のない(NULLの)レコードもヒットします。 まあ、あくまで代案として載せたサンプルコードなので、理解できてもできなくても別にかまわないですが。。。

trillian
質問者

補足

分かりづらい表現ですみません。 「Bのテーブルに値を持っていないデータ」というのは、 テーブルAにはデータがあるが、Bには対応するデータがないレコード、という意味です。 LEFT OUTER JOIN の構造でBのF4というカラムに"ABC"という条件を指定すると、  ・BにAと対応するデータを持っていて、かつb.F4='ABCであるレコード  ・BにAと対応するデータを持っていないレコード がヒットしてしまうのではないかと思います。

  • jamshid6
  • ベストアンサー率88% (591/669)
回答No.3

#2です。 結局検索条件に合わせてASPかVBScriptでSELECT文を組み上げているわけですよね? 書かれた案でもいいのでしょうけど、素朴な疑問として、AのフィールドとBのフィールドで検索条件の追加方法を変えるだけではだめなんでしょうか。 ざっくりこんな感じで。。 Dim sSQL,sWhere sSQL = "SELECT a.KEY,a.F1,a.F2,a.F3,b.F4,b.F5,b.F6" & _     " FROM TABLEA a" & _     " LEFT OUTER JOIN TABLEB b ON b.KEY=a.KEY" If bUseF1=True Then sWhere=sWhere & " AND a.F1='" & sF1 & "'" If bUseF2=True Then sWhere=sWhere & " AND a.F2='" & sF2 & "'" If bUseF3=True Then sWhere=sWhere & " AND a.F3='" & sF3 & "'" If bUseF4=True AND sF4="" Then sWhere=sWhere & " AND (b.F4='' OR b.F4 IS NULL)" If bUseF4=True AND sF4<>"" Then sWhere=sWhere & " AND b.F4='" & sF4 & "'" If bUseF5=True AND sF5="" Then sWhere=sWhere & " AND (b.F5='' OR b.F5 IS NULL)" If bUseF5=True AND sF5<>"" Then sWhere=sWhere & " AND b.F5='" & sF5 & "'" If bUseF6=True AND sF6="" Then sWhere=sWhere & " AND (b.F6='' OR b.F6 IS NULL)" If bUseF6=True AND sF6<>"" Then sWhere=sWhere & " AND b.F6='" & sF6 & "'" If LEFT(sWhere,4)=" AND" Then sWhere = " WHERE" & RIGHT(sWhere,LEN(sWhere)-4) sSQL=sSQL & sWhere あとは、外部結合の書式ですが「*=」はSQL Server 2005からはサポートされませんから、「LEFT OUTER JOIN」に慣れておいた方がいいですよ。

trillian
質問者

補足

ご返答ありがとうございます。 ご提示いただいたSQLですと、検索の際、Bのnull以外の検索値を指定した場合、Bのテーブルに値を持っていないデータもヒットしてしまうかと思います。 (Bの検索値に空白以外の値を入力した場合、検索結果はBにデータも持たないレコードを含まず、Bに検索値を持っているデータのみ表示させたい) なお、空白が指定できる項目は、Bにある項目のみになります。 外部結合に関しては、ご教示いただきましたように、今回の修正でLEFT OUT JOINに変更する予定でおります。

  • jamshid6
  • ベストアンサー率88% (591/669)
回答No.2

画面がVBなのか、Accessなのか、それ以外なのか。検索条件入力後のクエリはどのように構築しているか。 ・・が分からないので、純粋にSQL Serverに関する質問と考えて書きますが、 空白を指定できる検索条件が複数あったとしても、「空白またはNULL」の両方を満たすように条件を指定してあげるしかないと思います。 SELECT * FROM TABLEA a LEFT OUTER JOIN TABLEB b ON b.KEY=a.KEY WHERE a.FIELD1=@PARM1 AND ISNULL(a.FIELD2,'')=@PARM2 AND ISNULL(b.FIELD1,'')=@PARM3 AND ISNULL(b.FIELD2,'')=@PARM4 ... テーブルAのうち、NULLの入らない項目についてはISNULLはかぶせないようにし、条件はできるだけ最初の方に持ってくるのがいいでしょう。 検索条件をできる限り触りたくない場合、結合しているテーブルの方をビューにして、ビューの中でテーブルB側の 項目に全部ISNULLをかぶせてしまう手もあるかと思います。 CREATE VIEW VIEWA AS SELECT a.KEY1 KEY, a.FIELD1 AFIELD1, ISNULL(a.FIELD2,'') AFIELD2, ........ ISNULL(b.FIELD1,'') BFIELD1, ISNULL(b.FIELD2,'') BFIELD2 FROM TABLEA a LEFT OUTER JOIN TABLEB b ON b.KEY=a.KEY で、検索するときには SELECT * FROM VIEWA WHERE AFIELD1=@PARM1 AND AFIELD2=@PARM2 AND BFIELD1=@PARM3 AND BFIELD2=@PARM4 ...

trillian
質問者

補足

状況に関する記述が不足していまして、申し訳ありません。 環境 開発言語:ASP DB:SQLserver 問題の箇所は検索ボタンを押してからの動作で、SQLを投げているのはVBScriptです。 Bの項目に含まれる検索項目に入力があるとフラグをオンにし、 フラグがオンの場合:AND A.KEY = B.KEY フラグがオンでない場合:AND A.KEY *= B.KEY という条件にしています。 検索条件にnullの入らない項目はSQL上前に集結させております。 現状、いただいた回答により以下のような案を考えました。 (1)Aにデータを持ち、Bにデータを持たないレコードをserectしたビュー(Vα)を事前に作成しておく (2)検索時にnullが入る項目にすべてnullを指定された場合、  AとBにデータを持ち、かつ検索項目を満たすデータ(=内部結合で検索条件に一致するデータ)と、  Vαで検索条件に一致するデータをunionさせる  nullが入る項目に1つでもnull以外を指定された場合、Bにデータがあることが前提になるため、  Vαはunionさせない 上記の方法に矛盾がある、またはほかに方法がある場合、 ご教示いただければありがたいです。

  • rukuku
  • ベストアンサー率42% (401/933)
回答No.1

こんばんは データベースについては人様にアドバイスできるほどの経験はなく、自分自身が勉強しながら使ってる者です。 一番に思いつくのは外部結合のRIGHTとLEFTを間違っていませんか?ということです。 テーブルA、テーブルBのフィールドと問題のあるSQL文を提示してもらえれば、もう少しアドバイスできるかもしれません。

関連するQ&A

  • テーブルで一番古いレコードだけをSELECTしたい

    テーブルで一番古いレコードだけをSELECTしたいのですが、どうすれば良いでしょうか? ■背景 ・テーブルからデータを取得しようと思ったら、「id」及び「autoincrement」に該当するカラムがありませんでした ・日付に該当するカラムもありません ・「phpMyAdmin」で確認すると、いつも同じ並び順で表示されるので、格納したレコード順で表示されているのではないかと思いました ■質問 ・この時、そのテーブルで一番古いレコードだけをSELECTしたいのですが、どうすれば良いでしょうか? ・where?

    • ベストアンサー
    • MySQL
  • 2つのテーブルからレコードを抽出する方法

    お世話になります。MySQLに関する質問です。 TABLE1とTABLE2の2つのテーブルからレコードを抽出する際、 TABLE1からは全項目のデータを取得し、TABLE2からは一部の項目の データを取得したいと考えています。 条件は、TABLE1とTABLE2を[No]という項目の値で紐(ひも)づけます。 (1) SELECT * FROM TABLE1 (2) SELECT COL_A, COL_B, COL_C FROM TABLE2 上記(1)(2)のレコードを1つのSQLで取得する方法について、どなたかご教授願えますか?

    • ベストアンサー
    • MySQL
  • 一番新しいdatetime型列があるレコードを取得

    下記条件を満たすSQL文を知りたいのですが、どう書けばよいでしょうか? ■構成 Aテーブル ・「id」カラム ・「created_at」カラム … datetime型 ・「area」カラム Bテーブル ・「a_id」カラム ・「created_at」カラム … datetime型 ■前提 ・Aテーブルの1レコード(「id」カラム)に対して、0~複数のBテーブルレコード(「a_idカラム」)がある ・A.id = B.a_id ■欲しい内容 ・「Aテーブル」「Bテーブル」それぞれのカラム内容全部。※条件あり ▼条件1 Aテーブル「id」カラムに対応したBテーブルの「a_id」が複数ある場合には、該当Aテーブル内容+ Bテーブル「created_at」カラムの値が一番新しいレコードを返す(取得レコード数は常に1) ▼条件2 Aテーブル「id」カラムに対応したBテーブルの「a_id」がなかった場合には、該当Aテーブル内容+ Bテーブル側は何も返さない ▼条件3 ※同名カラムを取得する際には、カラム名先頭にそれぞれa、bを付与(「acreated_at」「bcreated_at」) ・後で、それぞれのテーブルカラムとして利用したいだけなので、それが出来れば形式にこだわりはありません

    • ベストアンサー
    • MySQL
  • テーブルのレコード件数取得について

    はじめまして。 postgresの「テーブルのレコード件数取得」について教えてください。 何も考えずに select count(*) from tblA; というSQLの記述をしていたのですが、レコード件数が30万件を超えた あたりから、結果が戻るまでに4~5秒もかかるようになりました。 もっと効率の良い(=短い時間)検索方法はあるのでしょうか? ちなみに postgres+C+PC-Soralis の組みあわせです。 マシンはPen4-2Ghz メモリーは512MBです。

  • 複数のテーブルの レコード件数所得

    sql初心者です。 php sql4.1を使って テーブルA・テーブルBの総レコード件数を所得がうまくできません。 テーブルAの◇◇が○○の含むレコード件数を所得は SELECT count(*) FROM テーブルA WHERE ◇◇ LIKE ○○ でできました。 テーブルA・テーブルBの◇◇が○○の含むレコード件数を所得はどうすればいいのでしょうか? よろしくお願いいたします.

    • ベストアンサー
    • MySQL
  • 登録テーブル全てのレコードカウントについて

    唐突で申し訳ありませんが、oracle の count について質問があります。 現在、複数のテーブルに各データ(レコード)が入っているのですが、 select 文でテーブル名を指定せず、登録されている全テーブルに対するレコード件数をカウントしたいのですが、どなたか教えていただけないでしょうか?よろしくおねがいします。。m(__)m <出力イメージ> TABLE_NAME   COUNT(*) ------- ----- 商品名        1250 連絡先        8700

  • PostgreSQL、テーブル比較で片方のテーブルにないレコードのみ表

    PostgreSQL、テーブル比較で片方のテーブルにないレコードのみ表示する方法 こんばんは、お世話になっております。 タイトル通りの質問です。 以下のテーブルがあったとします。 Aテーブル No.|data1|data2 ---+-----+---- 1 |a |10 2 |b |11 3 |c |12 4 |d |13 5 |e |14 Bテーブル No.|data1|data2 ---+-----+---- 1 |a |10 2 |b |11 3 |c |12 4 |d |13 5 |e |14 1 |f |10 2つのテーブルがあり、結合後条件の条件で 『=fのような直接的な指定はしないで』 Bテーブルのdataが『f』となっているもののみ表示させたいです。 WHEREの条件に 『Aテーブル.data1 <> Bテーブル.data1』 等を記述をしましたが理想の結果は得られませんでした。 postgresのバージョンは8.2、 pgAdminのバージョンは1.6.3 です。 何か方法をご存知の方がいらっしゃいましたら回答いただきたく思います。 不足な点があれば指摘してください。補足させていただきます。 以上です、よろしくお願いします

  • ACCESSで質問です。

    ACCESSで質問です。 テーブルA(複数企業)とテーブルB(Aの企業に対する対応状況)があります。 選択クエリにてAとBの2つのテーブルを電話番号でリレーションをもたせ、その企業の対応状況を検索し、結果をフォームに表示できるものを作りました。 しかし、企業(テーブルA)に対して複数の対応状況(テーブルB)があるため、フォームでBの対応状況分と同じ枚数のAレコードが表示されてしまいます。 クエリのプロパティで「固有のレコード」を「はい」にしても表示されてしまいます。 イメージでは、AテーブルとBテーブルの項目どれでも検索ができ、初めに検索結果をフォーム1で企業データを表示させ、コマンドボタンをクリックするとフォーム2で、その企業の対応状況が表示されるようにしたいのです。 現在検索は出来ていますが、フォーム1で同じ企業データレコードが複数表示されないようにしたいのです。 どのようにしたら出来ますでしょうか?アドバイスお願いします。 ・使用バージョンはACCESS2000です。 ・Aテーブルの企業データは重複なしです。 ・Aテーブルの主キーは電話番号です。 ・検索条件はA・Bの項目合わせて10項目で、全てIIFを使用して検索しています。 ACCESSを始めたばかりの初心者です。質問も初心者レベルですが、よろしくお願いします。

  • テーブルに新しいレコードを追加する方法について

    ACCESS2007を使っています。 フィールドに以下のような項目があるテーブルAがあります。 日付 | 名称 | 項目 | MIN(数値) | MAX(数値) | チェック(Yes/No) また、以下のような項目があるテーブルBがあります。 日付 | 名称 | 項目 | ナンバー(数値) このテーブルAに以下のようなデータが入っているとして 1/1 | あああ | いいい | 10  | 100 | No 1/1 | あああ | ううう | 1 | 20 | Yes テーブルBに以下のようにレコードを追加したいのです。 1/1 | あああ | いいい | 10   1/1 | あああ | いいい | 11    ・  ・  ・ 1/1 | あああ | いいい | 100 1/1 | あああ | ううう | 1 1/1 | あああ | ううう | 2   ・  ・  ・ 1/1 | あああ | ううう | 20 1/1 | あああ | ううう | blank  最終的には、テーブルBをソースとしてラベル印刷したいと思っています。 レコードセットとFor~Nextなどを使えばできそうな気がするのですが、???です。 どなたかご指南いただけませんでしょうか?

  • 2つのテーブルのデータまとめて取得したい

    SQL Server2008を使用しているのですが、どうのようにデータを取得すれば良いか わからず困っております。 例えば、 名前は違うが全く同じテーブルが2つあるとします。 テーブルAには6レコード、テーブルBには3レコードのデータが存在するとします。 この時、単純に6レコード+3レコードの 9レコード分をひとつのテーブルとしてデータを 取得するにはどのようなSQL文を書けばよいでしょうか? SELECT * FROM テーブルA, テーブルBでは18レコードもデータを取得してしまい、且つ フィールド数も増加してしまいます。 宜しくお願いいたします。