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

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

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

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

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

7回答

1721閲覧

MySQLの文字型 ~ varcharではなくintで返して欲しい

tiqua_nibio

総合スコア62

MySQL

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

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2020/02/24 13:57

編集2020/02/26 14:16

まず以下のSQLでテーブルを作成します。

MySQL 5.7.25-log
JDBC jdbc_4.3.15
Java 1.8

MySQL

1CREATE TABLE `new_table` ( 2 `id` INT NOT NULL AUTO_INCREMENT, 3 `a` INT NULL, 4 `b` INT NULL, 5 PRIMARY KEY (`id`)); 6 7 8insert into `new_table` 9(`a`, `b`)VALUES 10(0,1), 11(1,0), 12(0,0), 13(1,1), 14(0,1), 15(1,0), 16(0,0), 17(1,1), 18(0,1), 19(1,0), 20(0,0), 21(1,1); 22

次に、このSQLで結果を返してもらいます。具体的には、aが1であれば、5点を上げるというものです。

MySQL

1SELECT 2 COALESCE(SUM((CASE 3 WHEN (`a` = 1) THEN 5 4 ELSE NULL 5 END)), 6 0) AS `aa` 7FROM 8 new_table;

ここから、私のやりたいことです。

これによって返ってくるaaは、intではなく、varchar型のようです。
これをintで返してもらいたいと思います。どこか方法を変えればよろしいでしょうか?
よろしくおねがいします。


(追加)
SQLのプロフェッショナルより回答が付きましたので、詳しい事情をお伝えしたいと思います。

実はこれはJavaと連携しており、JavaからみたMySQLのメタデータは、intではなく、Stringとして解釈しているようです。
以下のソースコードはJavaをご存じない方にとっては難しいかもしれませんが、要はMySQLの方でintとして認識してもらえるように作れたら、Javaの知識は特に必要ないと思っております。

Java

1 String query = "SELECT * from `new_table` limit 0, 1;"; 2 Map<String, String> mp = new LinkedHashMap<String, String>(); 3 4 try { 5 6 Class.forName("com.mysql.jdbc.Driver"); 7 8 Connection conn = DriverManager.getConnection(Constant.JDBC_URL, Constant.PASS, Constant.ANGO); 9 java.sql.Statement st = conn.createStatement(); 10 ResultSet resultSet = st.executeQuery(query); 11 12 ResultSetMetaData metadata = resultSet.getMetaData(); 13 int column_count = metadata.getColumnCount(); 14 15 for (int i = 0; i < column_count; i++) { 16 17 mp.put(metadata.getColumnName(i + 1), metadata.getColumnTypeName(i + 1)); 18 19 } 20 21 } catch (Exception e) { 22 23 System.out.println("error"); 24 } 25 26

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

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

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

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

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

rubytomato

2020/02/25 10:02

MySQLのバージョン、JDBC Driverのバージョン、Javaのバージョンを質問に追記ください。 また、MySQLのInt型をJDBCドライバがVARCHARと認識するということは考えにくいので、念のため `show create table new_table`の結果も教えてください。
xebme

2020/02/25 12:00 編集

MariaDb、jdbcの組み合わでMetadataを取得するとBIGINT型でした。`aa`にSQLのcast(... as int)を適用するとDECIMAL型になりました。 たとえVARCHAR型でも内容が数字のみならResultSet#getLongやResultSet#getIntで数値を取得できるのですが、MetaDataを使うフレームワークをお考えですか?それなら上の CASTを考えてみたら。 MyslとJDBCドライバ、Javaのバージョンは?
tiqua_nibio

2020/02/26 14:17

`show create table new_table` CREATE TABLE `new_table` (\n `id` int(11) NOT NULL AUTO_INCREMENT,\n `a` int(11) DEFAULT NULL,\n `b` int(11) DEFAULT NULL,\n `new_tablecol` varchar(45) DEFAULT NULL,\n PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 でした。
tiqua_nibio

2020/02/26 14:18

cast、確かにできるかもしれないと思いますので試してみます。
rubytomato

2020/02/26 15:53

追記ありがとうございました。なるべく同じ環境を用意して動作確認を行った結果を回答しました。 それと一点確認させてほしいのですが、質問文にJDBC ドライバを > JDBC jdbc_4.3.15 と書かれていますが、MySQL Connector/jに4.3.15というバージョンは無いように思います。 使われているドライバのjarファイル名は何になりますか?
tiqua_nibio

2020/03/01 13:57

mysql-connector-java-5.1.46.jarのようです。
rubytomato

2020/03/04 12:49

> mysql-connector-java-5.1.46.jarのようです。 こちらのバージョンでも確認しましたが、MySQLのInt型はJavaのIntegerにマップされました。 また、以下のリファレンスでも確認しましたがMySQLのIntがJavaのjava.lang.Integerに変換されるのは仕様のようです。 5.5 Java, JDBC and MySQL Types https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-type-conversions.html 回答の方にも書きましたが、プログラムの問題というより環境に起因する気がします。 なので、他に確認することといったら、新しいデータベースを構築し、なるべくカスタマイズしない状態で接続確認するということくらいでしょうか。
tiqua_nibio

2020/03/08 04:19

有益な情報のページを教えていただき、ありがとうございます。詳しく書かれており、参考になります。 時間ができましたらデータベースの再構築など、色々と検証してみたいと思います。
guest

回答7

0

ResultSet
ResultSetのgetXXX()メソッドについて誰も書いていないので指摘しておきます。ソースコードに以下を追加しました。getLong()getBigDecimal()で数値を取得します。

Java

1for (int i = 0; i < column_count; i++) { 2 mp.put(metadata.getColumnName(i + 1), metadata.getColumnTypeName(i + 1)); 3} 4 5// ここから追加 ----------------------------------------------------------- 6System.out.println(mp); 7if (resultSet.next()) { 8 String b = "", c= ""; 9 for (String key : mp.keySet()) { 10 b += ((b.length()==0)?"":",")+resultSet.getLong(key); 11 c += ((c.length()==0)?"":",")+resultSet.getBigDecimal(key); 12 } 13 System.out.println(b); 14 System.out.println(c); 15} 16 17// ここまで追加 -----------------------------------------------------------

JDBCを使って実行したSQL。castを使って文字列を数値に、数値を文字列に変換。

SQL

1"select cast('987654321' as int) as `i`, cast(12345 as char) as `vc`" 2"select cast('9999999990' as decimal) as `i`, cast(3456 as char) as `vc`"

実行結果

Java

1{i=INT, vc=VARCHAR} 2987654321,12345 3987654321,12345 4{i=DECIMAL, vc=VARCHAR} 59999999990,3456 69999999990,3456

たとえ数値がvarchar型でも getLong()getBigDecimal()で変換できるのでJava側で問題になりません。

投稿2020/02/25 12:20

xebme

総合スコア1090

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

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

momon-ga

2020/02/26 01:13

他の方の回答のコメント欄を見ると 値でなくメタデータをINTで受け取りたいようです。 > メタデータは > {id=INT, a=VARCHAR, b=VARCHAR} > と出ます。ですので、VARCHARとして認識しているようです。これをINTになるようにしたいです。 castでintが取れるようなので解決に向かいそうですね。
tiqua_nibio

2020/02/26 14:28

ありがとうございます。当方、Javaで確かになんとか書けるのではありますが、tableは百個ぐらいあります。それなら、SQLを少し修正してから、どのtableにも適用できるような形(メソッド)にしたいと考えておりました。
xebme

2020/02/26 23:05

ResutSetのメタデータを利用する機能(フレームワーク)は、メタデータだけに頼ると硬直的。型変換機能も検討されるとよいでしょう。BeanUtilsに型変換機能があったと記憶しています。(釈迦に説法かもしれません) VARCHARは、たとえば、VIEWのネストが深いと型認識がゆるくなるのか、型不明ならVARCHARで値を保持すれば最も安全だろうと想像しました。根本的な解決を期待します。
tiqua_nibio

2020/03/01 13:35

確かにmetadataに頼ると良くないかもしれませんね。型変換が必要な場合、型変換をするような形に持っていく実装が必要かもしれません。検討してみます。
guest

0

以下の環境とプログラムで動作確認を行いました。この結果の通りINTをVARCHARと認識することはなかったので、原因は少なくともJavaプログラムには無いように思います。

環境

  • Windows 10
  • MySQL 5.7.26 Community Edition
  • Java 1.8
  • MySQL Connector/j 5.1.48

MySQL側

テーブルとテストデータの作成。

sql

1CREATE TABLE `new_table` ( 2 `id` int(11) NOT NULL AUTO_INCREMENT, 3 `a` int(11) DEFAULT NULL, 4 `b` int(11) DEFAULT NULL, 5 `new_tablecol` varchar(45) DEFAULT NULL, 6 PRIMARY KEY (`id`) 7) 8ENGINE = InnoDB 9DEFAULT CHARSET=utf8; 10 11INSERT INTO `new_table` (`a`, `b`) VALUES 12(0,1), 13(1,0), 14(0,0), 15(1,1), 16(0,1), 17(1,0), 18(0,0), 19(1,1), 20(0,1), 21(1,0), 22(0,0), 23(1,1);

作成したテーブルのスキーマ情報を確認。

sql

1> SELECT column_name, data_type,column_type FROM information_schema.columns WHERE table_name = 'new_table'; 2+--------------+-----------+-------------+ 3| column_name | data_type | column_type | 4+--------------+-----------+-------------+ 5| id | int | int(11) | 6| a | int | int(11) | 7| b | int | int(11) | 8| new_tablecol | varchar | varchar(45) | 9+--------------+-----------+-------------+ 104 rows in set (0.00 sec)

Javaで実行するSQLをMySQL Clientからも実行して確認。

sql

1> SELECT * FROM `new_table` LIMIT 0, 1; 2 3+----+------+------+--------------+ 4| id | a | b | new_tablecol | 5+----+------+------+--------------+ 6| 1 | 0 | 1 | NULL | 7+----+------+------+--------------+ 81 row in set (0.00 sec)

Java側

質問文に記載のプログラムとほぼ同じです。Eclipse上からJavaアプリケーションとして実行しました。

java

1import java.sql.Connection; 2import java.sql.DriverManager; 3import java.sql.ResultSet; 4import java.sql.ResultSetMetaData; 5import java.sql.SQLException; 6import java.sql.Statement; 7 8public class MetaDataCheck { 9 10 public static void main(String[] args) { 11 12 Connection conn = null; 13 try { 14 String jdbcUrl = "jdbc:mysql://localhost:3306/test_db"; 15 16 String query = "SELECT * FROM `new_table` LIMIT 0, 1"; 17 //String query = "SELECT COALESCE(SUM((CASE WHEN (`a` = 1) THEN 5 ELSE NULL END)), 0) AS c FROM `new_table`"; 18 19 conn = DriverManager.getConnection(jdbcUrl, "test_user", "test_user"); 20 Statement st = conn.createStatement(); 21 ResultSet rs = st.executeQuery(query); 22 23 ResultSetMetaData meta = rs.getMetaData(); 24 25 for (int i=0; i<meta.getColumnCount(); i++) { 26 String columnName = meta.getColumnName(i+1); 27 String columnTpeName = meta.getColumnTypeName(i+1); 28 String columnClassName = meta.getColumnClassName(i+1); 29 System.out.println(String.format("name:[%-13s] type:[%-8s] class:[%s]", columnName, columnTpeName, columnClassName)); 30 } 31 System.out.println(); 32 33 while (rs.next()) { 34 Integer id = rs.getInt("id"); 35 Integer a = rs.getInt("a"); 36 Integer b = rs.getInt("b"); 37 String n = rs.getString("new_tablecol"); 38 System.out.println(String.format("id:[%d] a:[%d] b:[%d] new_tablecol:[%s]", id, a, b, n)); 39 //BigDecimal c = rs.getBigDecimal("c"); 40 //System.out.println(String.format("c:[%f]", c)); 41 } 42 43 } catch (Exception e) { 44 e.printStackTrace(System.err); 45 } finally { 46 if (conn != null) { 47 try { 48 conn.close(); 49 } catch (SQLException e) { 50 e.printStackTrace(System.err); 51 } 52 } 53 } 54 } 55 56}

標準出力の内容
この内容の通りMySQLのInt型はJavaではIntegerにマップされています。

name:[id ] type:[INT ] class:[java.lang.Integer] name:[a ] type:[INT ] class:[java.lang.Integer] name:[b ] type:[INT ] class:[java.lang.Integer] name:[new_tablecol ] type:[VARCHAR ] class:[java.lang.String] id:[1] a:[0] b:[1] new_tablecol:[null]

また、下記のSQLL文を実行した結果も確認しました。

java

1String query = "SELECT COALESCE(SUM((CASE WHEN (`a` = 1) THEN 5 ELSE NULL END)), 0) AS c FROM `new_table`";

JavaではBigDecimalにマップされています。

name:[c ] type:[DECIMAL ] class:[java.math.BigDecimal] c:[30.000000]

なお、以下の環境でも動作確認を行いましたが結果は変わりませんでした。

  • MySQL 8.0.17 CE
  • OpenJDK 13.0.2
  • MySQL Connector/j 8.0.17

投稿2020/02/26 15:50

rubytomato

総合スコア1752

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

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

tiqua_nibio

2020/03/01 13:46

色々とお手数おかけし、ありがとうございました。なぜ、私の方ではvarcharとして認識されるのか、未だに不明です。
guest

0

NULLの時も0なので、1以外は0でも一緒と考えてCOALESCEを取りました。

sql

1SELECT SUM(CASE WHEN (a = 1) THEN 5 ELSE 0 END) AS aa FROM new_table;

COALESCEを使うケースも作成してみました。

sql

1SELECT SUM(COALESCE(CASE WHEN a = 1 THEN 5 ELSE NULL END, 0)) AS aa FROM new_table;

投稿2020/02/25 08:24

編集2020/02/25 08:51
amura

総合スコア333

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

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

tiqua_nibio

2020/03/01 13:36

SUMを使えば、たしかにintで返ってきているようです。
guest

0

ベストアンサー

的外れかもしれませんが・・・

MySQLの関数COALESCEの戻り値は、そもそもvarcharをmetadataとして返すのでは?
実行時の結果に合わせて動的に変わらないような気がします。

で、対処方法としては型キャスト(cast関数)をすれば、いけるのでは?(動作未確認)

投稿2020/02/25 01:37

momon-ga

総合スコア4826

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

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

tiqua_nibio

2020/03/01 13:58

おっしゃった回答の通りで、おおむね正しいようです。castは有効でした。
tiqua_nibio

2020/03/02 13:14

ありがとうございました。みなさん色々とご教示いただき、どれをベストアンサーに選ぶか迷いましたが、一番早く正答を回答していただいた方につけようと思いました。
guest

0

数値型で返却されそうですけど、直接SQLを試してみましたか?
Nullを挟むけどSum()がvarcharを返すとは思えません。
以下でも結果は同じはずですから、試してみて下さい。

SQL

1SELECT 2 cast(SUM(CASE WHEN `a`=1 THEN 5 ELSE 0 END) as UNSIGNED) AS `aa` 3FROM 4 new_table

投稿2020/02/24 14:10

編集2020/02/25 02:36
sazi

総合スコア25327

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

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

tiqua_nibio

2020/02/24 14:24

結果は確かに同じなんですが、Javaから見ると、Stringとして見えるようなんです。viewでは、文字型を指定できないみたいなので、どうしたらいいか、困っています。 質問に補足いたしました。
sazi

2020/02/24 15:46

いや、それは受け取るJava側の問題ですね。受け取る方での型を確認してみて下さい。
tiqua_nibio

2020/02/25 00:55

他のカラム(例えばカラムそのものを取り出しており、関数を使っていない) SELECT `a`, COALESCE(SUM((CASE WHEN (`a` = 1) THEN 5 ELSE NULL END)), 0) AS `aa` FROM new_table; とすれば、`a`のほうはintと認識されています。
sazi

2020/02/25 02:39 編集

javaでの受け取り時に暗黙変換されているんだと思いますけどね。 ※SQLの結果がdecimalなので文字に変換しているんだと思いますけど。 取り敢えず、CAST()してみて下さい。(回答変更済み)
tiqua_nibio

2020/03/01 13:36

ありがとうございます。castで成功しました。
guest

0

mpはMap<String, String>ですので、"カラム名"="INT"と文字列になりますがその事でしょうか?
メタデータは"INT"という文字列になると思うのですが。

投稿2020/02/24 16:14

junzi

総合スコア279

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

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

tiqua_nibio

2020/02/25 00:49

ありがとうございます。 メタデータは System.out.println(mp); で {id=INT, a=VARCHAR, b=VARCHAR} と出ます。ですので、VARCHARとして認識しているようです。これをINTになるようにしたいです。
guest

0

CREATE TABLE `new_table` ( `id` INT NOT NULL AUTO_INCREMENT, `a` INT NULL, `b` INT NULL, PRIMARY KEY (`id`)); INSERT INTO new_table VALUES ( 1,1,1) ,( 2,2,2); CREATE TABLE a as SELECT COALESCE(SUM((CASE WHEN (`a` = 1) THEN 5 ELSE NULL END)), 0) AS `aa` FROM new_table; CREATE TABLE b AS SELECT SUM(CASE WHEN `a`=1 THEN 5 ELSE 0 END) AS `aa` FROM new_table; SHOW CREATE TABLE a; SHOW CREATE TABLE b;
TableCreate Table
aCREATE TABLE a ( aa decimal(23,0) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8
TableCreate Table
bCREATE TABLE b ( aa decimal(23,0) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8

双方ともにmysql判定は「decimal」でしたが、何をもとにvarcharと思ったのでしょうか?

投稿2020/02/24 14:50

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問