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

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

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

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

Q&A

解決済

5回答

6264閲覧

レコードの2文字目をアルファベット(aから昇順)に置換するSQL文(追加質問2)

退会済みユーザー

退会済みユーザー

総合スコア0

MySQL

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

0グッド

0クリップ

投稿2016/08/08 09:13

編集2016/08/08 09:56

###前提
MySQLにて、データベースに入っているレコードに対し、
2文字目をアルファベット(aから昇順)に置換する
SQL文を作成しています。

###現状の動作と実現したい動作イメージ
・SQL実行前
ID / 枝番/ ユーザID
A001 / 001 / E001
A001 / 002 / E002
: / : / :
A001 / 026 / E026
A002 / 001 / F001
A002 / 002 / F002
A003 / 001 / F002

・SQL実行後(現状)
ID / 枝番/ ユーザID
Aa01 / 001 / E001
Ab01 / 002 / E002
: / : / :
Az01 / 026 / E026
A02 / 001 / F001
A02 / 002 / F002
A03 / 001 / F002

※上から順にaからzを振られているが、
27番目以降は2文字目にnullが置換されている

・SQL実行後(理想)
ID / 枝番/ ユーザID
Aa01 / 001 / E001
Ab01 / 002 / E002
: / : / :
Az01 / 026 / E026
Aa02 / 001 / F001
Ab02 / 002 / F002
Aa03 / 001 / F002

※ユーザIDとID、セットでPK扱い。
27番目以降でもユーザIDとIDのセットが新しくなっていれば、
2文字目を「a」から開始する。
※ユーザIDとIDのセットが27以上存在する場合は
別箇所でエラー処理する予定なので今回は考慮していただかなくて大丈夫です。

###現在試していること
ストアドプロシージャで、
IDとユーザIDでgroup byし、その結果をカーソル変数に代入、
ループしながら2文字目を書き換える、というSQL文で
実現しようとしています。

###現在作成しているSQL文

SQL

1delimiter // 2create procedure alphabet() 3 4BEGIN 5 DECLARE done INT DEFAULT 0; 6 DECLARE _count INT; 7 DECLARE cur CURSOR FOR #カーソル変数 8 SELECT 9 count(*) 10 FROM 11 sampleTable 12 GROUP BY ID,USER_ID 13 ORDER BY branch ASC; # branch:枝番 14 DECLARE EXIT HANDLER FOR NOT FOUND SET done = 1; 15 16 OPEN cur; 17 WHILE done !=1 DO 18 FETCH cur INTO _count; 19 IF _count > 1 AND _count < 27 THEN 20 SET @i:=0; 21 UPDATE 22 sampleTable AS tbl3, 23 (SELECT 24 MID('abcdefghijklmnopqrstuvwxyz',@i:= @i+1,1) AS ID, 25 USER_ID 26 FROM 27 (SELECT @i:= 0) AS dum, 28 29 (SELECT DISTINCT 30 USER_ID 31 FROM 32 sampleTable ORDER BY 1 33 ) AS tbl2 34 ) AS tbl1 35 SET 36 tbl3.ID = concat(MID(tbl3.ID,1,1),tbl1.ID,MID(tbl3.ID,3,2)) 37 WHERE 38 tbl3.USER_ID = tbl1.USER_ID; 39 40 ELSE UPDATE sampleTable SET ID = ID; 41 END IF; 42 END WHILE; 43 CLOSE cur; 44END 45// 46 47CALL alphabet()

###追記
現在、ストアドプロシージャで実現しようとしていますが、
他の方法があれば、特にストアドプロシージャにはこだわりません。

以上です。
複雑で申し訳ないですが、
ご不明点等ございましたらご指摘ください。

宜しくお願い致します。

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

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

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

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

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

yambejp

2016/08/08 09:20

A001の26番めのでーたが「AZ01 / 026 / E026」となっていますが「Az01」でよいですか?
退会済みユーザー

退会済みユーザー

2016/08/08 09:24

ご指摘ありがとうございます。「Az01」が正しいです。(本文も修正しました)
guest

回答5

0

asahina_devさんの、ユーザ変数を使った方法ですが

MySQLのマニュアルと
OracleACEのAketiJyuuzouさんとyoku0825さんと
日本オラクルの木村明治さんによると
1ステートメントでユーザ変数を複数回使用した場合の
ユーザ変数の評価順序は未定義です。
http://qiita.com/AketiJyuuzou/items/cced9b70cc714b382d98

具体的には、
@i:= 0
が全ての @i:= @i+1の評価よりも、前に評価されることが保証されませんので、
update結果は、IDに重複が発生する可能性があります。

要するに、(select @i:=0)とのクロスジョインにおいて、
(select @i:=0)の行数は評価するけど
select句は、後回しに評価した場合ですね。

投稿2016/09/05 03:05

tamako

総合スコア120

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

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

0

ベストアンサー

sql

1delimiter // 2create procedure alphabet() 3 4BEGIN 5 DECLARE done INT DEFAULT 0; 6 DECLARE _count INT; 7 DECLARE cur CURSOR FOR #カーソル変数 8 SELECT 9 count(*) 10 FROM 11 sampleTable 12 GROUP BY ID,USER_ID 13 ORDER BY branch ASC; # branch:枝番 14 DECLARE EXIT HANDLER FOR NOT FOUND SET done = 1; 15 16 OPEN cur; 17 WHILE done !=1 DO 18 FETCH cur INTO _count; 19 IF _count > 1 AND _count < 27 THEN 20 SET @i:=0; 21 UPDATE 22 sampleTable AS tbl3, 23 (SELECT 24 -- MID('abcdefghijklmnopqrstuvwxyz',@i:= @i+1,1) AS ID, 25 MID('abcdefghijklmnopqrstuvwxyz',MOD(@i:= @i+1, 26),1) AS ID, 26 USER_ID 27 FROM 28 (SELECT @i:= 0) AS dum, 29 30 (SELECT DISTINCT 31 USER_ID 32 FROM 33 sampleTable ORDER BY 1 34 ) AS tbl2 35 ) AS tbl1 36 SET 37 tbl3.ID = concat(MID(tbl3.ID,1,1),tbl1.ID,MID(tbl3.ID,3,2)) 38 WHERE 39 tbl3.USER_ID = tbl1.USER_ID; 40 41 ELSE UPDATE sampleTable SET ID = ID; 42 END IF; 43 END WHILE; 44 CLOSE cur; 45END 46// 47 48CALL alphabet()

でいけるような(ループさせるなら MOD であまりを計算)

投稿2016/08/08 11:44

asahina_dev

総合スコア610

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

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

退会済みユーザー

退会済みユーザー

2016/08/09 08:29

以前の質問から引き続きご回答ありがとうございました。 本当に助かりました! また宜しくお願い致します。
guest

0

こんな感じでどうでしょう?

SQL

1UPDATE sampleTable 2SET 3 ID = MID('abcdefghijklmnopqrstuvwxyz', cnt, 1) 4FROM ( 5 SELECT 6 A.ID 7 , A.userID 8 , count(*) + 1 AS cnt 9 FROM sampleTable A 10 JOIN sampleTable B 11 ON A.ID = B.ID 12 AND A.userID > B.userID 13) C 14WHERE sampleTable.ID = C.ID 15AND sampleTable.userID = C.userID 16

KotoriMaturiさんの指摘を受けて修正しました
(GROUP BYもぬけてましたし)

SQL

1UPDATE 2 sampleTable T1 3 , ( 4 SELECT 5 A.ID 6 , A.userID 7 , count(*) + 1 AS cnt 8 FROM sampleTable A 9 JOIN sampleTable B 10 ON A.ID = B.ID 11 AND A.userID > B.userID 12 GROUP BY 13 A.ID 14 , A.userID 15 ) T2 16SET 17 T1.ID = MID(T1.ID, 1, 1) 18 + MID('abcdefghijklmnopqrstuvwxyz', T2.cnt, 1) 19 + MID(T1.ID, 3, 1) 20WHERE T1.ID = T2.ID 21AND T1.userID = T2.userID 22

UPDATEのFROM副問い合わせはすっかりSQLServerのノリで書いてましたf(^-^;


追記
そのまま残すべきところを忘れていたので追加しました

投稿2016/08/08 09:36

編集2016/08/08 14:15
kutsulog

総合スコア985

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

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

退会済みユーザー

退会済みユーザー

2016/08/08 09:52

ご回答ありがとうございます! ただ、4行目のFROMでシンタックスエラーが出ています。 (MySQL Workbenchにて確認しております) お手数をおかけして申し訳ございませんが、ご確認いただけますでしょうか。 何卒宜しくお願い致します。
Panzer_vor

2016/08/08 10:27

> kutsulogさん UPDATEのFROM句はPostgreSQLのベンダ拡張のようです。 MySQL用に置き換える必要がありそうですね
Panzer_vor

2016/08/08 11:04

再び横槍ですが、 UPDATE句でのFROM指定はSQL Serverのベンダ拡張でもあるんですね。 それにしてもUPDATEの書き方はベンダ毎に差異があるので地味に厄介ですね…^^;
退会済みユーザー

退会済みユーザー

2016/08/09 08:34

> kutsulogさん ご回答ありがとうございます! a~zの二週目で期待していた動きを実現できなかったので。 私の仕様説明が分かりにくいなか、考えていただいたのに申し訳ございません。 >KotoriMaturiさん 私の質問に補足いただき、ありがとうございました! PostgreSQLの書き方ということも分からず質問しておりました。。
guest

0

たとえばこんな感じでどうでしょう?
ユーザーIDは関係なさそうなので省略しました

元データ

SQL

1create table sampleTable(ID VARCHAR(10),枝番 VARCHAR(10),unique(ID,枝番)); 2insert into sampleTable values('A001','001'),('A001','002'),('A001','003') 3,('A001','004'),('A001','005'),('A001','006'),('A001','007'),('A001','008') 4,('A001','009'),('A001','010'),('A001','011'),('A001','012'),('A001','013') 5,('A001','014'),('A001','015'),('A001','016'),('A001','017'),('A001','018') 6,('A001','019'),('A001','020'),('A001','021'),('A001','022'),('A001','023') 7,('A001','024'),('A001','025'),('A001','026'),('A002','001'),('A002','002') 8,('A003','001');

UPDATE

SQL

1update sampleTable as t1 2,(select ID,枝番,char((select count(*)+97 from sampleTable as t3 where t3.ID=t4.ID and t3.枝番<t4.枝番)) as rank 3from sampleTable as t4) as t2 4set t1.ID=concat(substr(t1.ID,1,1),t2.rank,substr(t1.ID,3,3)) 5where t1.ID=t2.ID and t1.枝番=t2.枝番;

投稿2016/08/08 11:20

yambejp

総合スコア114823

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

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

退会済みユーザー

退会済みユーザー

2016/08/09 08:38

ご回答ありがとうございます! 改めて私の質問文を読むと確かにユーザIDがいらないように読めますね、、 仕様説明に曖昧な部分があり、申し訳ございませんでした。。
guest

0

よく質問文を読むと前回と要件が異なっていたのですね^^;
あれから再考してみましたが、
他の回答者さんの回答以外で、これだというクエリが力及ばず思いつきませんでした。

ただサンプルにあげてるデータだけを見ると、
0. IDが切り変わるタイミングで採番をリセットする
0. さらに言うとID毎に枝番が振られる

上記ルールが成り立ってるように見えるので、

  • 登録された枝番が必ず1から始まる
  • 枝番には欠番が存在しない

が保証されているのであれば難しく考えず、
単純に枝番を数値にキャストして、
その数値を基にアルファベットを取り出すで良いような気はします。

※以下履歴のために残してますが、今回の要望にはかなっていないため無視して下さい

アルファベット置き換え用テーブルを追加して・・・

SQL

1CREATE TABLE LETTERS( 2 SEQNO INTEGER(3) -- 連番 3, LETTER VARCHAR(1) -- アルファベット 4)

連番には0~25にa~zを設定し、
SEQNO LETTER
0 a
1 b
** -- 中略 -- **
25 z

以下の感じのクエリでどうでしょうか?
ただ現在、MySQLでの検証環境がないのでエラーが出るかもしれないです…

SQL

1SET @row = -1; 2UPDATE table, 3 ( 4 SELECT 5 T2.* 6 , @row:=@row + 1 AS ROW_NUM 7 FROM 8 ( 9 SELECT 10 T1.MIN_ID 11 , T1.UPD_KEY 12 FROM 13 ( 14 SELECT 15 MIN(ID1) AS MIN_ID 16 , ID2 AS UPD_KEY 17 FROM 18 table 19 GROUP BY 20 ID2 21 ) T1 22 ORDER BY T1.MIN_ID 23 ) T2 24 ) T3 25 INNER JOIN LETTERS T4 26 ON MOD(T3.ROW_NUM, 25) = T4.SEQNO 27SET 28 ID1 = CONCAT(SUBSTR(ID1, 1, 1), T4.LETTER, SUBSTR(ID1, 3)) 29WHERE 30 ID2 = T4.UPD_KEY

・追記
MOD(T1.ROW_NUM, 25)と文字列変換テーブルの連番で結合かけてるので、
zまで採番が終わるとaから循環し直す仕様にしてます。

投稿2016/08/08 10:23

編集2016/08/08 23:45
Panzer_vor

総合スコア1636

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

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

退会済みユーザー

退会済みユーザー

2016/08/09 08:35

前回に引き続きご回答いただき、ありがとうございます。 何度も考えていただき大変恐縮です。 仕様説明が分かりにくく申し訳ございませんでした。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問