20210329のMySQLに関する記事は5件です。

DockerイメージのMySQL5.6と5.7はタイムゾーン設定が異なる

MySQL5.6から5.7に移行するにあたって、開発環境を整理していたらDockerイメージのデフォルトのタイムゾーンが変わっていることに気付いた。

MySQL 5.6のタイムゾーン設定

5.6のデフォルトのタイムゾーンは以下の通り設定されていた。

mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | UTC    |
| time_zone        | SYSTEM |
+------------------+--------+
2 rows in set (0.00 sec)

そのため、Dockerfileで以下のコマンドを実行して、タイムゾーンを変更していた。

RUN cp -p /usr/share/zoneinfo/Japan /etc/localtime

MySQL 5.7のタイムゾーン設定

5.7のデフォルトのタイムゾーンは以下の通りだった。

mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | JST    |
| time_zone        | SYSTEM |
+------------------+--------+
2 rows in set (0.00 sec)

system_time_zoneがロケールの時間帯を採用するように変更されたらしい。
これによって最初から日本時間で処理されるようになった。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SQL テーブルの結合

こちらの記事では、私が学んだSQLについて記載しております。
自身の忘れないためのメモとしております。
間違っている部分もあるかもしれませんので、ご了承ください。

テーブルの結合とは

テーブル同心をある条件で結合することにより、[正規化なし]の状態を作り出すこと。

テーブルの[正規化]は重要!!

・データ管理が容易になる 
・データ容量の削減
→特別な意図がなければ、データは正規化する。

例
ユーザー情報の中で都道府県のデータを取得する際に
”文字列”でデータを保存してしまうと、データに負荷がかかる。
テーブルは別にして、都道府県のみのデータにすることで、”文字列”をまとめられる。

[正規化なし]
テーブルusers 
id  name  都道府県
1  田中  大阪
2  鈴木  大阪
3  佐藤  大阪

[正規化あり]
テーブルusers        テーブル都道府県
id  name  都道府県    id   都道府県
1  田中   2      1  東京
2  鈴木   2      2  大阪
3  佐藤   2      3  京都

テーブルを分け正規化することで、データ管理がしやすくなり、容量を削減可能。
もし今後、都道府県の「大阪」が「太田」と変更された場合でも、テーブル都道府県の変更を行えばすぐに対応可能になる。

内部結合 inner joinで結合可能

***記述方法***
select
     テーブル名a.id,
     テーブル名b.表記したいカラム名   ←テーブル名b.nameなど
from
     テーブル名a
inner join
     テーブル名b
on テーブル名a.id = テーブル名b.a_id; ←2つのテーブルのidを結合する

***テーブル名は省略も可能***
テーブル users, orders

select
    u.id,
    u.name,
    o.name
from 
    users u   ←users as uとして変更可能。asは省略も可能なので左のような記載になる。
inner join
    orders o
on u.order_id = o.id;

外部結合 left outer join/right outer join

inner joinではnullは表記せず、left outer joinではnullも表記する
select
    u.last_name,
    u.id,
    o.user_id,
    o.id
from
    users u
-- inner join
left outer join
    orders o
on u.id = o.user_id
order by u.id;

3つ以上のテーブルの結合 inner join連続で記述

テーブル users, orders, orders_details
select  
      u.id,
      u.name,
      o.name,
      od.price
from
    users u
inner join
    orders o
on u.order_id = o.id
inner join
    orders_details od
on od.order_id = o.id;

一対多もしくは多対多の関係は、確認して行うこと!!!

テーブルの足し算 union/union all

テーブル1とテーブル2で列数(カラム名)を合わせる必要があります!!
テーブル users ,adomin
select
    email,
    name,
    gender
from
    users
union       ←unionのみだと重複は省略。union allだと重複も表記される。
select
    email,
    name,
    gender
from
    admin
;


***条件分岐*** order byのみ全体の1つしか記述できない!!!!!!!
select
    email,
    last_name,
    first_name,
    gender
from
    users
where
    gender = 1
union
select
    email,
    last_name,
    first_name,
    gender
from
    admin_users
where
    gender = 2
order by gender    ←order byは全体記述の最後!
;

補足

主キー/外部キー

・主キー・・1つの行を特定できる列(カラム)のこと
・外部キー・・・他のテーブルの関連付けに使う列(カラム)のこと

記述順序

記述順序                   実行順序
select・・・・・取得カラムの指定          from・・・・・・・対象テーブルの指定
from・・・・・・・対象テーブルの指定         結合処理
結合処理                    where・・・・・・絞り込み条件式の指定
where・・・・・・絞り込み条件の指定         group by・・グループ化の条件を指定
group by・・グループ化の条件指定        having・・・・・グループ化した後の絞り込み条件を指定
having・・・・・グループ化した後の絞り込み条件指定  select・・・・・取得カラムの指定
order by・・・並び替え条件指定          order by・・並び替え条件を指定
limt・・・・・・・・取得する行数の制限         limit・・・・・・取得する行数の制限

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【MySQL】複数のカラムで重複しているデータを見つける方法

データ解析に使ったので、メモ
サブクエリ内では、countを実行するだけ。
メインクエリ内では、countが1以上のものは重複していると言えるので、以下のような形でできる。

select * from (
    select concat(column1, '-', column2) as token,
        COUNT(*) as cnt
        FROM table_name GROUP BY (token)
) as contents WHERE cnt > 1;

解析に使っただけだが、実際のプロダクションコードとしてで扱うには、あまりよくない気がする。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JDBCドライバ】MySQL Connector/J 8.0ダウンロード手順

はじめに

自身がJava学習中にDB接続の環境を整える際に悩んだので、
JDBCドライバのダウンロードから環境のセットアップまでを記載します。

使用環境

開発環境:paizacloud
Javaバージョン:13.0.1
Apache Tomcatバージョン:9.0.41
DB:MySQL
JDBCバージョン:8.0.23

1.JDBCのインストーラーダウンロード

image.png

image.png

image.png

image.png

2.インストーラ起動

image.png

3.connect/Jをダウンロード

image.png
<ファイルダウンロード先(例)>

C:\Program Files (x86)\MySQL\Connector J 8.0\mysql-connector-java-8.0.23.jar

4.jarファイルを配置

ダウンロードしたドライバ(jarファイル)をWEB-INF\libに配置する。

5.Javaには下記のように記載する。

ドライバ名がバージョンで異なるそうです。

ドライバのバージョンが8.0系の場合

Class.forName("com.mysql.cj.jdbc.Driver");

※ドライバのバージョンが8.0系よりも前の場合

Class.forName("com.mysql.jdbc.Driver");

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

税込から税抜を求めるには切り上げ?切り下げ?→ケースバイケースで要注意な件

4月から税込み表示が義務化され、また世のエンジニアが苦労する中、逆に税込から税抜を求めるの思った以上に苦労した話です。
一般的な小売では税込から税抜を求める状況はないと思いますが、相対取引で定価が無い場合は税込価格から決まることはザラです。

具体例として10096円〜10099円の間の価格でお話ししますと
10097円は÷1.1して切り捨てた9179円が正解です。
10099円は÷1.1して切り上げた9181円が正解です。

なぜなら双方とも誤って切り上げたり、切り下げると共に9180円になり、そこから税込価格を逆算すると10098円一択となってしまい元に値と矛盾するからです。ちなみに

10098円は割り切れる整数なので、切り捨て切り上げ関係なく、9180円の一択になります。
10096円は切り捨てて9178円、切り上げて9179円としてどちらでも良いのですが、それらからの税込み価格の計算は、端数の取扱次第で10095〜10097円まで幅広く解釈することができます。

これらを踏まえ実装としては、税抜価格netが最大化する按分になるceilでまず計算してみて、そこから税込の逆算が矛盾を起こす場合のみ、floorを採用する条件分岐が必要になります。
MySQLなら以下の通りです。

mysql> SELECT
    -> taxed,
    -> case when floor(ceil(taxed/1.1)*1.1)=taxed or ceil(ceil(taxed/1.1)*1.1)=taxed then ceil(taxed/1.1) else floor(taxed/1.1) end as net
    -> FROM (
    -> SELECT 10096 AS taxed UNION
    -> SELECT 10097 AS taxed UNION
    -> SELECT 10098 AS taxed UNION
    -> SELECT 10099 AS taxed
    -> ) prices;
+-------+------+
| taxed | net  |
+-------+------+
| 10096 | 9179 |
| 10097 | 9179 |
| 10098 | 9180 |
| 10099 | 9181 |
+-------+------+
4 rows in set (0.01 sec)

MySQLは問題ありませんでしたが、実装には浮動小数点の問題があり要注意です。
端的に以下に例示すると100円の税込みは110円のはずですが、どちらも111円になります。体感的にはもはやバグです。

JavaScriptによる例
Math.ceil(100*1.1) // 111
pythonによる例
import math
math.ceil(100*1.1) # 111

このリスクに対応するため8桁以降を丸めた処理を挟んで以下のようになりました。

pythonによる例
from math import floor, ceil
{taxed: ceil(round(taxed / 1.1, 8)) if floor(round(ceil(round(taxed / 1.1, 8)) * 1.1, 8)) == taxed or ceil(round(ceil(round(taxed / 1.1, 8)) * 1.1, 8)) == taxed else floor(round(taxed / 1.1, 8)) for taxed in [10096, 10097, 10098, 10099]}
# {10096: 9179, 10097: 9179, 10098: 9180, 10099: 9181}

1万円までの全価格を走査して統計とったスクリプトを書いたので、貼っておきます。
価格(整数)の集合全体の8割は割った後に切り上げ切り下げどちらでも良いのですが、残り1割ずつは切り上げ限定か切り下げ限定の困ったちゃん価格なのが分かります。

from math import floor, ceil
import pprint
result = {}

for taxed in range(100, 10100):
    recalc = {
        "FF": floor(round(floor(round(taxed / 1.1, 8)) * 1.1, 8)),
        "CF": floor(round(ceil(round(taxed / 1.1, 8)) * 1.1, 8)),
        "FC": ceil(round(floor(round(taxed / 1.1, 8)) * 1.1, 8)),
        "CC": ceil(round(ceil(round(taxed / 1.1, 8)) * 1.1, 8)),
    }
    key = tuple(k for k, v in recalc.items() if v == taxed)
    if len(key) == 0:
        print(taxed)
        raise
    result[key] = [*result.get(key, []), taxed]
    print(taxed, key, recalc)

pprint.pprint({k: {
    "min": min(v),
    "max": max(v),
    "len": len(v), } for k, v in result.items()})

税抜き価格の計算は税率で割って丸めるだけ、そんなふうに考えていた時期が俺にもありました。。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む