質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Q&A

解決済

1回答

588閲覧

【MySQL】後ろから読んで最初の()を拾ってくるという書き方

tajix_japan

総合スコア132

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

0グッド

0クリップ

投稿2017/08/05 03:39

下記のようなテーブル title があります。
カラム(div,sub,sub_no)

div sub sub_no
1000 カローラ販売(1)
1001 セリカ販売(31)
1002 ブルーバード販売(14)
1003 コロナ販売(15)

上記の末尾にある()内の数字を sub_no に書き写すMySQLを組みました。

mysql

1 2UPDATE `title`,(SELECT `div`, `sub`, TRIM(SUBSTRING(`sub`, LOCATE('(',`sub`)+1, LOCATE(')',`sub`)- LOCATE('(',`sub`)-1)) AS `ABC` FROM `title` ) as AAA SET `title`.`sub_no`= `AAA`.`ABC` WHERE `title`.`div`= `AAA`.`div`; 3

上記では想定通り下記のようになります。

div sub sub_no
1000 カローラ販売(1) 1
1001 セリカ販売(31) 31
1002 ブルーバード販売(14) 14
1003 コロナ販売(15) 15

上記の場合は問題なかったのですが、下記だと問題が生じました。

テーブル title
div sub sub_no
1000 カローラ(東京)販売(1)
1001 セリカ販売(31)
1002 ブルーバード(多摩)販売(14)
1003 コロナ販売(15)

上記の場合、本来であれば「カローラ(東京)販売(1)」では1を表示してほしいのですが、先頭から()を探しに行くらしく最初に出てくる東京が表示されてしまいます。
ブルーバード(多摩)販売(14) も同様に多摩が表示されます。

div sub sub_no
1000 カローラ(東京)販売(1) 東京
1001 セリカ販売(31) 31
1002 ブルーバード(多摩)販売(14) 多摩
1003 コロナ販売(15) 15

質問です。
MySQLで後ろから読んで最初の()を拾ってくるという書き方はありませんでしょうか?
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

sql

1UPDATE title SET sub_no = SUBSTRING_INDEX(SUBSTRING_INDEX(sub, '(', -1), ')', 1);

https://dev.mysql.com/doc/refman/5.6/ja/string-functions.html#function_substring-index

文字列 str から、区切り文字 delim が count 回出現する前の部分文字列を返します。count が正の値の場合は、(左から数えて) 最後の区切り文字の左側にあるすべてが返されます。count が負の値の場合は、(右から数えて) 最後の区切り文字の右側にあるすべてが返されます。

動作結果

sql

1mysql> CREATE TABLE title ( 2 -> `div` INT, 3 -> sub VARCHAR(16), 4 -> sub_no INT 5 -> ); 6Query OK, 0 rows affected (0.02 sec) 7 8mysql> INSERT INTO title (`div`, sub) VALUES 9 -> (1000, 'カローラ(東京)販売(1)'), 10 -> (1001, 'セリカ販売(31)'), 11 -> (1002, 'ブルーバード(多摩)販売(14)'), 12 -> (1003, 'コロナ販売(15)'); 13Query OK, 4 rows affected (0.01 sec) 14Records: 4 Duplicates: 0 Warnings: 0 15 16mysql> SELECT * FROM title; 17+------+--------------------------------------+--------+ 18| div | sub | sub_no | 19+------+--------------------------------------+--------+ 20| 1000 | カローラ(東京)販売(1) | NULL | 21| 1001 | セリカ販売(31) | NULL | 22| 1002 | ブルーバード(多摩)販売(14) | NULL | 23| 1003 | コロナ販売(15) | NULL | 24+------+--------------------------------------+--------+ 254 rows in set (0.00 sec) 26 27mysql> UPDATE title SET sub_no = SUBSTRING_INDEX(SUBSTRING_INDEX(sub, '(', -1), ')', 1); 28Query OK, 4 rows affected (0.00 sec) 29Rows matched: 4 Changed: 4 Warnings: 0 30 31mysql> SELECT * FROM title; 32+------+--------------------------------------+--------+ 33| div | sub | sub_no | 34+------+--------------------------------------+--------+ 35| 1000 | カローラ(東京)販売(1) | 1 | 36| 1001 | セリカ販売(31) | 31 | 37| 1002 | ブルーバード(多摩)販売(14) | 14 | 38| 1003 | コロナ販売(15) | 15 | 39+------+--------------------------------------+--------+ 404 rows in set (0.00 sec)

ちなみにこのご質問は、以前のご質問とほぼ同じ内容です。
https://teratail.com/questions/78649

もう少し慎重に過去の投稿などを調べてみてください。


()の存在しない場合は、

div sub sub_no
1003 クラウン販売  
のようにsub_noをNULLにしたいと考えています。

「()の存在しない場合」の他にも「正しくない形式」のパターンを挙げだすと、キリがありません。
例えば

  • ほげ(5a)のように、() の中に数字以外の文字が混ざっている
  • ほげ 10)のように、カッコの開閉が対応していない

など。

なので、以下のように「正しい形式」のレコードと「正しくない形式」のレコードを別々に更新するのが良いと思います。

「正しい形式」に対する UPDATE文

sql

1UPDATE title 2SET sub_no = REPLACE(SUBSTRING_INDEX(sub, '(', -1), ')', '') 3WHERE sub REGEXP '.*\\([0-9]+\\)$';
「正しくない形式」に対する UPDATE文

sql

1UPDATE title 2SET sub_no = NULL 3WHERE sub NOT REGEXP '.*\\([0-9]+\\)$';

ただし、MySQL の REGEXP関数はマルチバイトセーフではないため、正しい/正しくない を誤って判定する可能性はあります。
https://dev.mysql.com/doc/refman/5.6/ja/regexp.html

REGEXP および RLIKE 演算子はバイト単位で機能するため、マルチバイトセーフではなく、マルチバイト文字セットを使用すると想定外の結果が生成される可能性があります。

もし、上の方法でもうまくいかない場合は、スクリプトを組んで1行ずつ

形式のチェック -> UPDATE

を繰り返すのが、結局は最も確実な方法だと思います。

投稿2017/08/05 05:25

編集2017/08/05 06:23
KiyoshiMotoki

総合スコア4791

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tajix_japan

2017/08/05 05:35

有難うございます。 SELECT REPLACE(SUBSTRING_INDEX(sub, '(', -1), ')', '') AS number FROM `table`; で組んでいたのですが、下記の悪さをすることがわかりました。 div sub sub_no 1000 カローラ(東京)販売(1) 1 1001 セリカ販売(31) 31 1002 ブルーバード(多摩)販売(14) 14 1003 コロナ販売(15) 15 上記まではできます。 しかし、 1003 クラウン販売 のように()が存在しない例があった場合に、 下記のようにsubの全文を取ってきてしまうことが判明しました。 div sub sub_no 1003 クラウン販売  クラウン販売 ()の存在しない場合は、 div sub sub_no 1003 クラウン販売   のようにsub_noをNULLにしたいと考えています。 そのため、上記のSUBSTRING_INDEXを廃止し、新しい方法を考えているところです。 もちろん、SUBSTRING_INDEXを使って、()がなけれはNULLを返すという方法でも 構いません。 ご助言いただけましたら幸いです。 よろしくお願いいたします。
KiyoshiMotoki

2017/08/05 06:24

回答に追記しました。 ご確認ください。
tajix_japan

2017/08/05 09:01

有難うございます。 「正しい形式」のレコードと「正しくない形式」のレコードを別々に更新することで対応できました。 助かりました。深く御礼申し上げます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問