文字列内の数値を検索に使う場合の手法

このQ&Aのポイント
  • WinXPでの開発で、データベースはOracle、開発ソフトはC++Builder5を使用しています。
  • テーブルのデータはTB1、TB2、TB3の3つがあり、TB2とTB3のidは必ずTB1に存在します。
  • TB3のdataはカンマ区切りの文字列で、実際のデータはコード、サイズ1、サイズ2となっています。検索にはトリガーを使用する方法もありますが、最も高速な手法はファイルを使用する方法です。
回答を見る
  • ベストアンサー

文字列内の数値を検索に使う場合の手法

検索の仕方で質問があります。 WinXPでの開発です。 データベースはOracle、開発ソフトはC++Builder5です。 以下のようなテーブルとデータがあります。 TB2,TB3のidは必ずTB1に存在します。 TB3のdataには、カンマ区切りの文字列が入っています。 dataのカンマ区切りの内容は "コード,サイズ1,サイズ2" となっています。 実際はこのような単純なデータではないので、カラム分けするのは 設計時に難しかったようです。 ------------------------------ CREATE TABLE TB1 ( id number, name varchar2(20) ); 1 sample1 2 sample2 3 sample3 ------------------------------ CREATE TABLE TB2 ( id number, keyno number ); 1 100 3 200 ------------------------------ CREATE TABLE TB3 ( id number, data char(200) ); 1 aaa,0.1,0.2 2 bbb,0.3,0.4 ------------------------------ たとえば TB2.keynoが100であり、TB3.dataのサイズ1が0.1のデータのTB1.nameを取りだす という場合、どのようなSQL文になるのでしょうか? TB3のデータは読み込んだ後に一旦文字列を分解して コード、サイズ1、サイズ2を取得しないことには検索出来ないと思います。 一番高速な手法はどうなるでしょうか? トリガーを使って、作業用のテーブル作ってやればいい、 みたいなことを言われたのですが、トリガーは違うのでは?と思いながら 手法を悩んでいます。 ローカルデータベースのようなファイルを使ってやる方法になるのでしょうか? アドバイスをお願いします。

  • mm666
  • お礼率92% (58/63)
  • Oracle
  • 回答数3
  • ありがとう数3

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

  • ベストアンサー
回答No.1

SELECT TB1.name FROM TB1 INNER JOIN TB2 ON TB2.id=TB1.id INNER JOIN TB3 ON TB3.id=TB1.id WHERE TB2.keyno=100 AND TB3.data LIKE '%,0.1,%' でどうでしょうか。

mm666
質問者

お礼

早速のアドバイスありがとうございます! こんなにすっきり書けるのですね。 もしも数値が、0.1ではなく範囲指定だった場合はダメでしょうか?

その他の回答 (2)

  • Siegrune
  • ベストアンサー率35% (316/895)
回答No.3

まず、 >トリガーを使って、作業用のテーブル作ってやればいい、 >みたいなことを言われたのですが、 は、TB4を作る。 CREATE TABLE TB4 ( id number, data1 varchar2(200) data2 number(18,3) data3 number(18,3) ); 1 aaa 0.1 0.2 2 bbb 0.3 0.4 TB3のInsert/Update/Deleteトリガーを作って、 TB4を更新する って趣旨でしょうね。 それはさておき。 >ORA-01722:数値が無効です。 を防ぎたいなら、CAST(の後にNVLを入れるだけで対応はできます。 AND CAST(NVL(・・・,0) AS DECIMAL(2,1)) といった感じですね。(Nullなら0に置き換える処理です。) でも、本当にそれでいいの? ## ま、その前に、ANo1/2をみていて、要件を小出しにするのはやめましょう~。 ## と言いたいところですが。 (1)逆じゃないの?と思う点 TB2.keynoが100であり、TB3.dataのサイズ1が0.1のデータのTB1.nameを取りだす これはいいのですが、 TB2.keynoが100であり、TB3.dataのサイズ1が0.15のデータのTB1.nameを取りだす とかしたいのでは? (つまり、問い合わせ時の値が0.1と0.2の間ならすべての場合で、  TB3の1を対象にしたいということでは?) (2)idって検索条件につかっていいの? INNER JOIN TB3 ON TB3.id=TB1.id という検索条件でいいのかな? もしそうなら、TB1とTB3に分けている理由が良く分からない。 TB1の中にDATAを作ればしまいのように思えるため。 (ま、あえて分ける理由が思いつかないわけではないのですが。) TB1の 1 sample1 に対して、TB3の複数のレコードが対応するんじゃないのかな? という疑問。 (3)TB3のdata char(200)の中身は? 本当に、 1 aaa,0.1,0.2 という形で1個しかないの? 1 aaa,0.1,0.2,aab,0.3,0.5,aac,0.6,0.9 とか複数あるのでは? と疑問に思ってしまいます。 ## 大丈夫です。というならそれでいいけど、要求事項の小出しはやめてくださいね。

mm666
質問者

お礼

アドバイスありがとうございます! > TB3のInsert/Update/Deleteトリガーを作って、 > TB4を更新する > って趣旨でしょうね。 Oracleに新たなテーブルを追加するのではなく、C++Builder上でというニュアンスでした。 そのため、検索するタイミングでトリガーという意味が分かりませんでした。 これは指示の間違いだったのかもしれません。 > を防ぎたいなら、CAST(の後にNVLを入れるだけで対応はできます。 ありがとうございます! > ## ま、その前に、ANo1/2をみていて、要件を小出しにするのはやめましょう~。 > ## と言いたいところですが。 申し訳ありません。 実際にはテーブルの内容もテーブル数も膨大で サンプル用の記述がよくなかったです。 これからこうならないよう注意します。 ありがとうございます。 > (1)逆じゃないの?と思う点 > (2)idって検索条件につかっていいの? 完全に私の質問用に作成した仮テーブルの内容が悪いせいで ご迷惑おかけしました。 テーブルを分ける理由などは正直昔から存在しているデータベースで 誰が設計したのかもわからない状態です。 何かを増やすたびに、よく分からないものになった可能性もあります。 > (3)TB3のdata char(200)の中身は? > 本当に、 > 1 aaa,0.1,0.2 > という形で1個しかないの? はい、これは必ず1個と決まっています。 色々とアドバイス戴きありがとうございました。 お手数おかけした上に、色々と不可解な内容となったことをお詫びいたします。

回答No.2

>もしも数値が、0.1ではなく範囲指定だった場合はダメでしょうか? AND CAST(SUBSTR(TB3.data,INSTR(TB3.data,',')+1 ,INSTR(TB3.data,',',1,2)-INSTR(TB3.data,',')-1) AS DECIMAL(2,1)) BETWEEN 最小値 AND 最大値 です。 (結構大変ですので、フィールドを内容単位に分割される事を推奨します)

mm666
質問者

お礼

ありがとうございます。 目的を達成出来そうです! ただ、TB3.dataに数値の入っていないもの(カンマだけ)があり、 ORA-01722:数値が無効です。 が出てしまいます。 書式をすでにあるコーディングに合わせると、以下のようになってしまっています。 ※ごちゃごちゃするのでTB2の条件を外しています select TB1.name from TB1 where exists( select * from TB3 where TB1.id=TB3.id and cast( substr(TB3.data,~,~) AS DECIMAL(2,1) ) BETWEEN 最小値 and 最大値 ); このとき、TB3.dataにカンマだけのデータが存在すると エラーとなっている気がします。

関連するQ&A

  • 組み合わせの検索方法

    数字の組み合わせ毎に情報を管理しようと思うのですが、 以下のようなテーブル構成を考えました。 CREATE TABLE COMBINATIONS ( COMBINATION_ID NUMBER, INFO VARCHAR2(100) ); CREATE TABLE ELEMENTS ( COMBINATION_ID NUMBER, ELEMENT_NUMBER NUMBER ); 例としては: <COMBINATIONS> COMBINATION_ID INFO -------------- ---- 1 ABC 2 DEF 3 GHI <ELEMENTS> COMBINATION_ID ELEMENT_NUMBER -------------- -------------- 1 1 1 2 2 100 2 200 3 100 3 200 3 300 です。 1,2の組合せの場合→ABC 100,200の組合せの場合→DEF 100,200,300の組合せの場合→GHI のような具合です。 このように、数字の組合せを条件にINFOを 取得するには、どのようなSQL文がよいでしょうか。 データベースはOracleです。

  • データベース:主キーが文字列の場合IDを振るべき?

    テーブルの主キーが文字列の場合、 その主キーの文字列を通し番号に置き換えて、 その文字列は別テーブルに移したほうが検索が速いですか? 例えば、テーブルが CREATE TABLE spec ( test_name VARCHAR(40) NOT NULL, upper_limit NUMERIC(17,7), lower_limit NUMERIC(17,7), PRIMARY KEY(test_name) ); で、40文字という長いテスト項目名の場合、 CREATE TABLE spec ( test_id INTEGER NOT NULL, upper_limit NUMERIC(17,7), lower_limit NUMERIC(17,7), PRIMARY KEY(test_id) ); と CREATE TABLE test ( test_id INTEGER NOT NULL, test_name VARCHAR(40) NOT NULL, PRIMARY KEY(test_id) ); という二つのテーブルに分けたほうが検索は速くなりますか? (もちろん、結合する時間も含めてです。) もし速くなるとしても、文字数が3文字など少ない場合は 通し番号に置き換えてもきっと効果は薄いですよね? 何文字以上の文字列なら通し番号に置き換えたほうが速いですか? 皆さんはどのように決めていますか?

  • カンマ区切りの文字列にPOSTデータをもぐりこませたい

    PHPでデータベースに挿入するデータを作成する段階で困っています。 作成したいデータは数字をカンマ区切りで形成しようとしています。 例は $_POST["p2"]="2"というデータがあれば 0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0・・・ という感じで $_POST["p8"]="6"というデータがあれば 0,0,0,0,0,0,0,6,0,0,0,0,0,0,0・・・ で70個の数字をカンマで区切った形で表現したいです。 どのようにしたら良いでしょうか? よろしくお願いします。

    • ベストアンサー
    • PHP
  • oracle pl/sql のコマンド終端子は「;」?「/」?

    oracleのsqlを書くときにコマンドの終わりに 「;」を書きますか? 「/」を書きますか? 例えば ===== sample1.sql ===== CREATE TABLE TB1 (IT1 VARCHAR(1)) ; COMMENT ON TABLE TB1 IS 'TB1のコメント' ; ===== sample1.sql ===== でも ===== sample2.sql ===== CREATE TABLE TB1 (IT1 VARCHAR(1)) / COMMENT ON TABLE TB1 IS 'TB1のコメント' / ===== sample2.sql ===== でも、同じ動きをしますが、どちらを使いますか? すべて「;」 すべて「/」 使い分けがある。 どちらでも良いが統一するに越したことはない。 好き嫌いのアンケートではありません。 人に聞かれた時に説明できる理由が欲しいです。 以上、よろしくおねがいします。

  • 文字列の検索 集計

    エクセルデータにて     A      B      C 1  ABC    ○○○    XYZ 2  ABC    ○○○    PQR 3  DEF    ×××    XYZ 4  DEF    ×××    PQR 5  DEF    ×××    HIJ *アルファベット、記号は文字列 において、下記形式にしたい場合はどの様な手法がありますでしょうか?     A      B      C 1  ABC    ○○○    XYZ PQR    2  DEF    ×××    XYZ PQR HIJ その際、Cに表示させる方法は、1)連続形式、2)カンマ区切り、3)別列の追加 が考えられると思いますが、どの形式でも構いません。(理想は2ですが) 初心者質問ですが、宜しくお願いします。

  • 大文字/小文字の区別しないで検索したい場合

    データベース:ORACLE9i いつもお世話になっています♪ いきなり質問ですが、 例えばこういうデータがテーブルに 入っているとします。 ID  NAME ----------- 1 AAA1 2 BBB2 3 CCC3 ----------- そこで下記のSQLを実行するとBBB2はヒットしません。 select * from test_tbl where name like '%b%'; 大文字/小文字を区別しないで検索する方法はないでしょうか? よろしくお願いします♪

  • テーブルごとに文字コード指定

    データベースの文字コードをUNICODEにしたいのですが、 レンタルサーバーを使っており、データベースはEUCのものしか使えません。 そこでテーブルごとに文字コードを指定して作成しようと思ったのですが、 うまくUNICODEのテーブルができません。 以下の記述でEUCのデータベースにUTF-8のテーブルを作成しています。 どこか間違っていますでしょうか? ------------------------------ create table テーブル名 (  id integer,  name varchar(120) ) CHARACTER SET utf8; ----------------------------- お詳しい方がおられましたらご回答下さい。 宜しくお願い致します。

    • ベストアンサー
    • MySQL
  • SQLでのレコード更新、追加処理

    Windows7 32bit MySQL5.5を使用しています。 テーブルのスペースが崩れてしまっていて見づらいかと思いますが よろしくお願いします。 ・table B +------+------------------+------+ | id | name | id_A | +------+------------------+------+ | 1 | 手順書作成 | 1 | | 2 | レビュー | 1 | | 3 | 開発 | 2 | | 4 | 社内・社外研修 | 3 | +------+------------------+------+ (id=主キー、name=文字列、id_A=テーブルAを参照するための外部キー) ↓ 1回だけ以下のプログラムを実行し、table Cを生成します create table C (SELECT * FROM B); alter table C add flag Boolean default FALSE; ↓ ・table C +------+------------------+------+------+ | id | name | id_A | flag | +------+------------------+------+------+ | 1 | 手順書作成 | 1 | 0 | | 2 | レビュー | 1 | 0 | | 3 | 開発 | 2 | 0 | | 4 | 社内・社外研修 | 3 | 0 | +------+------------------+------+------+ その後、Bが不定期に更新されるため、どこかの タイミングで、同様にCにも更新情報を反映したいのです。 ↓ ・更新されたtable B +------+------------------+------+ | id | name | id_A | +------+------------------+------+ | 1 | 手順書作成 | 1 | | 2 | レビュー | 1 | | 3 | 開発 | 2 | | 4 | 社内研修 | 3 | | 5 | 社外研修 | 3 | +------+------------------+------+ ↓ ・table C +------+------------------+------+------+ | id | name | id_A | flag | +------+------------------+------+------+ | 1 | 手順書作成 | 1 | 1 | | 2 | レビュー | 1 | 0 | | 3 | 開発 | 2 | 0 | | 4 | 社内研修 | 3 | 1 | ←このレコードは更新したい | 5 | 社外研修 | 3 | 0 | ←このレコードは追加したい +------+------------------+------+------+ どのように指定をすればいいでしょうか。 思いつくのは create table temp( select B.id, B.name, B.id, C.flag from B left join C on(C.id=B.id)); drop table c; create table c(select * from temp); drop table temp; という方法ですが、もう少しスマートな処理方法がないか、 そして、default値が反映されたものにしたいのです。 (上記を実行すると以下になります) ・table temp +------+------------------+------+------+ | id | name | id_A | flag | +------+------------------+------+------+ | 1 | 手順書作成 | 1 | 1 | | 2 | レビュー | 1 | 0 | | 3 | 開発 | 2 | 0 | | 4 | 社内研修 | 3 | 1 | | 5 | 社外研修 | 3 | NULL |←NULLではなく、FALSEとしたい +------+------------------+------+------+ どうぞ宜しくお願いします。

    • ベストアンサー
    • MySQL
  • postgresをAccessから操作、しかし#Deleted ?

    postgresでテーブルを作成 CREATE TABLE test_table (id serial , name text); というテーブルを作成しODBCを使いaccessからデータを追加すると なぜかすべての行に #Delete と表示されてしまいます。 しかし更新をするとAuto Numberもしっかり振られないようも更新されているのですが いまいち理解できません。 もし、対策がお分かりの方がいましたらご教授お願いいたします。

  • カンマを削除

    IDとNAMEがあり、値は以下になります。 ID NAME 1 西武 2 巨人 3 ソフトバンク そのIDとNAMEを取得し、NAMEについてはカンマ区切りで連結をし、 ID、NAMEはアンカタグを設定します。 NAMEの値をカンマ区切りにしているのですが、NAMEの値の最後にまで カンマが付加されてしまいます。 西武,巨人,ソフトバンク, ←ココ カンマ区切りをrtrimで削除出来ると思ったのですが、うまくいきません。 カンマを削除出来る方法または、他に良い方法があればアドバイス頂けないでしょうか。 以上、よろしくお願い致します。 for($i = 0; $i<10;$i++){ $array[i] = array("ID".[$i] => "NAME".[$i]); } foeach($array as $key => $value){ foreach($value as $id => $name){ <a href="aaa.php?id=$key">$name.","</a> } }

    • ベストアンサー
    • PHP