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

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

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

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

Q&A

解決済

2回答

194閲覧

MySQL 5.7 で、全レコードの指定カラムにランダムなひらがなn文字を UPDATE したい

munekun

総合スコア93

MySQL

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

0グッド

0クリップ

投稿2024/12/25 17:43

編集2024/12/25 17:51

実現したいこと

下記のように CREATE, INSERT したレコードがあります。
この nameカラムを、ランダムなひらがな10文字で UPDATE したいです。

SQL

1CREATE TABLE `test_users` ( 2 `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 `name` VARCHAR(100) DEFAULT '' 4); 5 6INSERT INTO `test_users` (`name`) VALUES ('aaa');

発生している問題・エラーメッセージ

phpMyAdmin の SQL タブに、後述する該当のソースコードの UPDATE をコピペし実行したものの、下記のエラーとなってしまいました。

MySQL のメッセージ: ドキュメント #1366 - Incorrect string value: '\x800G0F0...' for column 'name' at row 11

該当のソースコード

こちらがエラーとなった UPDATE です。

SQL

1UPDATE `test_users` 2SET `name` = ( 3 SELECT GROUP_CONCAT(c SEPARATOR '') 4 FROM ( 5 SELECT CHAR(CONV(HEX(FLOOR(12353 + RAND() * 83)), 16, 10)) AS c 6 FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION 7 SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) tmp 8 ) chars 9);

試したこと

試したこと(1) カラムの確認

エラーを見ると '\x930u0O0...' の表示があるので文字コードのせいかと思いました。
そこで SHOW FULL COLUMNS FROM test_users; で確認しましたが、name カラムは utf8mb4_general_ci でした。

試したこと(2) 半角英文字の UPDATE

そしてひらがなでなく下記のような半角英文字なら無事 UPDATE できました。

SQL

1UPDATE `test_users` 2SET `name` = ( 3 SELECT GROUP_CONCAT(CHAR(FLOOR(97 + RAND() * 26)) SEPARATOR '') 4 FROM ( 5 SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION 6 SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 7 ) tmp 8);
試したこと(3) ひらがなの INSERT

また、ひらがなでも下記 INSERT なら無事できました。

SQL

1INSERT INTO `test_users` (`name`) VALUES ('あああ');
試したこと(4) 文字コードを再確認

SHOW VARIABLES LIKE 'character_set%'; を実行すると、結果は下記でした。

character_set_client: utf8mb4
character_set_connection: utf8mb4
character_set_database: utf8mb4
character_set_server: utf8mb4

補足

バージョンは SELECT VERSION(); して 5.7.27-log の表示でした。

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

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

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

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

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

guest

回答2

0

ベストアンサー

ひらがなのリストを作っておいてfunctionで処理すれば楽でしょう

sql

1drop function if exists rnd_hiragana ; 2delimiter // 3create function rnd_hiragana(input INT) 4returns varchar(100) deterministic 5begin 6declare org varchar(100); 7declare ret varchar(100); 8set org='あいうえお'; 9set ret=''; 10while char_length(ret) < input do 11set ret=concat(ret,substring(org,ceil(rand() * char_length(org)),1)); 12end while; 13return ret; 14end ; 15// 16delimiter ;

test

sql

1create table tbl (id int primary key auto_increment,val varchar(20)); 2insert into tbl(val) values('あああ'),('いいい'),('ううう'),('えええ'),('おおお'); 3update tbl set val=rnd_hiragana(10);

投稿2024/12/26 00:47

編集2024/12/26 00:52
yambejp

総合スコア116921

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

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

munekun

2024/12/26 09:14

驚きでした。MySQL も php や JavaScript などと同様に function を定義できるのですね。 そしてそれを set で呼ぶと・・。へぇぇ、大変勉強になりました。 無事問題も解決しました。ありがとうございます。
guest

0

unicodeのコードポイントの数値と、UTF-8で符号化されたバイト列は別物です。

UTF-8の文字コード表とかで確認すると分かりやすいのですが
平仮名は3バイトの 0xE381800xE38296辺りで不連続な範囲に定義されています。

mysql では以下のように確認できます

sql

1SELECT HEX('ぁ'); -- => E38181 2SELECT HEX('あ'); -- => E38182 3SELECT HEX('ぃ'); -- => E38183 4SELECT HEX('い'); -- => E38184 5-- 略 6SELECT HEX('ゖ'); -- => E38294

なので、UTF-8の数値ベースでのランダム生成はめんどくさいです。

代替案としてutf32とかならコードポイントで指定できて手っ取り早いと思われます。
こちらは連続範囲なのでランダム生成もしやすいです

sql

1SELECT HEX(CONVERT('ぁ' USING utf32)); -- => 00003041 ... 0x3041 = 12353 2SELECT HEX(CONVERT('あ' USING utf32)); -- => 00003042 3SELECT HEX(CONVERT('ぃ' USING utf32)); -- => 00003043 4SELECT HEX(CONVERT('い' USING utf32)); -- => 00003044 5-- 略 6SELECT HEX(CONVERT('ゖ' USING utf32)); -- => 00003096

コードポイントの数値ベース≒utf32で文字化させると

sql

1SELECT CHAR(12353 USING utf32); -- => ぁ 2 3SELECT CHAR(FLOOR(12353 + RAND() * 86) USING utf32); -- => ランダムなひらがな1文字 ※*83でも良い

ちなみに半角英文字だとうまくいくというのは
asciiコード範囲(1バイトというか7bitまで)では
unicodeのコードポイント・UTF-8の符号化バイト列のいずれとも互換性を持つように設計されているからです。

投稿2024/12/25 22:34

pecmm

総合スコア745

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

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

munekun

2024/12/26 09:15

お詳しい方ばかりですね・・ どういう理屈でできないのかわからなかったので、pecmm様のご回答も大変参考になりました。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.34%

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

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

質問する

関連した質問