こんにちは。石川さんです。ChatGPT、何でも答えてくれるので、仕事のお悩みを聞いてもらいました。
CSVファイルはデータの中にカンマが含められません
事の発端は、今開発中のシステムでのお話です。連携用のデータの中にカンマがありまして、そのままCSVデータとして送信すると、エラーになってしまいました。ま、CSVはカンマ区切りの値ですから、カンマは何らかの処置をしてあげなければいけません。ぼくとしてはデータを「”」ダブルクォーテーションでくくるのがお好みなのですが、要望は半角カンマは全角に置き換えてください、ということでした。ORACLEからSQLを使ってデータを取出していましたので、このSQLを変更するのが楽でよさそうですね。そこで、TRANSLATEを使って置き換えることに決めました。イメージはこんな感じになります。
-- 修正前 SELECT 商品コード||','||商品名||','||単価 FROM 商品マスタ; -- 修正後(TRANSLATEを使って半角カンマ「,」を全角カンマ「,」に置き換える) SELECT 商品コード||','||TRANSLATE(商品名,',',',')||','||単価 FROM 商品マスタ;
そう、色々と調べて、これでうまくいくね、というときに閃きました。ChatGPTに聞いてみたら、ちゃんと教えてくれるのでしょうか。気になって聞いてみました。
Oracleで半角カンマを全角カンマに置き換える方法を教えてください。
そうするとですねぇ、ぼくが調べたTRANSLATEではく、REPLACEをおすすめしてきました。なるほど。この場合は、書き方の違いは関数名だけですね。
-- おすすめ結果 SELECT REPLACE('1,2,3,4', ',', ',') FROM dual;
そこで、次の質問です。
translateではなくreplace関数を利用する理由は何でしょうか?
そうすると、関数の違いを説明してくれて、利点を述べてくれました。その上で何と、置換対象が一つしかない場合はREPLACEの方が単純で実行速度が速くなる、と、教えてくれました。ご存知だと思いますがTRANSLATEは指定された文字列中の文字を対応させて変換してくれます。REPLACEは指定された単語を指定した単語へ変換してくれます。なので、それは本当のような気がしましたが、置換する文字が増えるなどの拡張性を考えた場合、TRANSLATEの方がいいような気がしたので、更に質問を続けます。
translateよりreplaceの方が実行速度が速いのですね。知りませんでした。本当でしょうか。そして、今後の拡張性を考慮した場合はtranslateを利用しておいた方がよいと思いますがいかがでしょうか?
この質問に対する回答では、拡張があるならTRANSLATE使ってね、と言ってもらいました。ただ、先程の質問を繰り返したような感じだったせいか、同じような回答でした。さらに、具体的にどれくらい速いのか知りたくなって聞いてみました。
では、translateとreplaceの速度の違いはどれくらいあるのでしょうか?
こんな無茶ぶりでもちゃんと答えてくれました。テーブルを作ってランダムなデータを1万件投入してUPDATEで更新した様子と、その実測した結果を示してきました。ワオ!
TRANSLATE
関数を使用した場合: 2.9秒REPLACE
関数を使用した場合: 0.6秒
いや~、これはすごいですね!ちょっと感動しました。お礼を述べて一旦終了したのですけど、、、そんなに違うかなぁ、、と思い、自分でも実測してみることにしました。1万件のデータを作って、半角の3を全角の3に置き換えて、3333を取り出す、というのを実験してみました!
-- まずはTRANSLATE with s(n) as ( select 1 n from dual union all select n + 1 from s where s.n < 10000 ) select * from s where translate(to_char(n),'3','3') = '3333'; -- 次にREPLACE with s(n) as ( select 1 n from dual union all select n + 1 from s where s.n < 10000 ) select * from s where replace(to_char(n),'3','3') = '3333'; --【実測します!】-- SQL> with s(n) as ( 2 select 1 n from dual 3 union all 4 select n + 1 from s where s.n < 10000 5 ) 6 select * from s 7 where translate(to_char(n),'3','3') = '3333'; N ---------- 3333 経過: 00:00:00.15 SQL> with s(n) as ( 2 select 1 n from dual 3 union all 4 select n + 1 from s where s.n < 10000 5 ) 6 select * from s 7 where replace(to_char(n),'3','3') = '3333'; N ---------- 3333 経過: 00:00:00.15 SQL>
結果が出ました。どちらも0.15秒です!やはり、2.9秒は怪しいと思いました。(笑)
1回目より2回目の方の実行速度が速くなるのはOracleがバッファキャッシュを利用しているのでよくある話なのかも、と、いうことで、再度質問してみました。
ちょっと気になったので再度質問します。先程の実行結果はtranslateよりreplaceを先に実行した場合、結果が変わってくるということはありますでしょうか?
そうすると、少々時間が経ってから「申し訳ありませんが、私の前回の回答に誤りがありました。実際には、TRANSLATE
関数の方がREPLACE
関数よりも実行速度が速いことが多いです。私の回答が混乱を招いてしまったこと、お詫び申し上げます。」と素直に間違いを認められました。で、ちょっと追加説明してから「再度、前回の回答が誤りであったことをお詫び申し上げます。」ですって。丁寧過ぎでしょ!
いや、感動しました。ChatGPT、すごいね!!!