20190226のMySQLに関する記事は4件です。

CakePHPでのDB更新処理の2つの場合(idで指定 or whereで指定)の方法について

バージョンはCakePHP3.2です。
DBはMySQLを使ってます。

下記の条件についてそれぞれの方法を書いていきます

  1. idで更新するrowを指定する場合
  2. whereで更新するrowを指定する場合


1. idでupdateするrowを指定する場合

<?php
use Cake\ORM\TableRegistry;
// ~ 略 ~ 
// MembersTableの読み込み
$this->loadModel('Members');
// DBとの通信開始
$this->Members->connection()->begin();
// updateするrowをidで指定
$qurey = $this->Members->get('10');
// updateするcolumnの値を代入
$qurey->address = 'Kanagawa';
$qurey->age = '21';
// dataがあれば更新,無ければ挿入を行いつつ、処理結果をresultに代入。
$result = $this->Members->save($query);

if ( $result === false ) {
    // もし失敗したらロールバック
    $this->Members->connection()->rollback();
} else {
    // 失敗していなければコミット
    $this->Members->connection()->commit();
}


2. whereでupdateするrowを指定する場合

<?php
use Cake\Datasource\ConnectionManager;
use Cake\ORM\TableRegistry;
// ~ 略 ~
// MembersTableの読み込み
$this->loadModel('Members');
$connection = ConnectionManager::get('default');
// updateするcolumnの値を代入
$membernew = array(
    'address' => 'Kanagawa',
    'age' => '21'
);
// DBとの通信開始
$this->Members->connection()->begin();
// 更新するrowをwhereで探して取得する。
$query = $this->Members->find()
                  ->where(['name' => 'Gaku'])
                  ->where(['address' => 'Tokyo'])
                  ->where(['age' => '20'])
                  ->first();

if(isset($query)) {  
    // queryにデータがあれば更新処理にする。
    $member = $this->Members->patchEntity($query, $membernew);
} else {
    // データが無ければ挿入処理にする。
    $member = $this->Members->newEntity($membernew);
} 
// 上で指定した処理を実行しつつ結果を代入する
$result = $this->Members->save($member);

if ( $resource_result === false ) {
    // もし失敗したらロールバック
    $this->Members->connection()->rollback();
} else {
    // 失敗していなければコミット
    $this->Members->connection()->commit();
}

以上です。

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

Slick+MySQLでdatetimeやtimestampをjava.time.*に変換したい【Slick3.3以降】

はじめに

この間怒りに任せてあげたSlickでいつの間にかjava.time.*がサポートされてた話ではMySQLのdatetimetimestampjava.time.LocalDateTimeに相互変換されませんって話でした。
しかも以前はサポート対象外だったおかげて暗黙の変換を書いておけば問題なかったんですが、3.3以降、自分の環境ではjava.time.*系の変換を書いちゃうとどっかで衝突すんのかコンパイルが通らなくなってしまいました(上記前記事参照)。

という訳で今回はどうにかして変換できるようにしてみます。

環境

scala: 2.12
slick: 3.3

型を作ってしまおう

しょうがないので間に型を咬ませます。
代表してdatetimeをサポートしてみます。

case class MySQLDateTime(value: String) {

 def toLocalDateTime: LocalDateTime =
    LocalDateTime.parse(value, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
}

回りくどい気もしますが、値としてdatetimeStringで保持し、LocalDateTimeとして出力できるようにしています。

テーブルではこんな感じ

class TestTable(tag: Tag) extends Table[Test](tag, "test") {
  // 抜粋
  def testDate = column[MySQLDateTime]("test_date")
  // 抜粋
}

このままでは当然MySQLDateTime型は変換できないのでコンパイルは通りません。

暗黙の変換

上記テーブルに下記の暗黙の変換を追加します。

implicit lazy val mySqlDateTimeType: JdbcType[MySQLDateTime] with BaseTypedType[MySQLDateTime] =
  MappedColumnType.base[MySQLDateTime, java.sql.Timestamp](
    t => java.sql.Timestamp.valueOf(t.value),
    u => MySQLDateTime(u.toLocalDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
  )

テーブルからはjava.sql.Timestampとして受けて相互変換可能としています。DateTimeFormatter...云々はどこぞに固定値として生やした方が良いでしょう。

おわりに

timestampdatetimeも同様に書くことができると思います。

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

Mysqlでカラム名を検索する

コマンド

とりあえず、コマンドが分かれば検索できるので最初に書いときます。
※mysqlで動かしましたが他のDBでは動かしてません。

sql
select
  *
from
  information_schema.columns 
where
    COLUMN_NAME = "カラム名"
    and table_schema = "データベース名"; 

これだけだと、表示されるselectが多いから適宜「*」を変えて検索

検索したいカラム名が含まれるテーブル名を検索したい時

sql
select
  table_name, column_name
from
  information_schema.columns 
where
    COLUMN_NAME = "カラム名"
    and table_schema = "データベース名"; 

名称備忘

information_schema.columns

テーブル内のカラムに関する情報を表示してくれる。

以下のリンクが公式のサイト
mysalServerの公式

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

複合ユニークのうちの一つのカラムのint値をすでに使われてるint値に更新したい

MySQLでこういったテーブルとデータがあったとする。データに任意の順番をもたせたいが、順番の値は重複を許可したくないといったケースを想定している。下記テーブルでいくと sort カラムが順番の値を保持しているものとする。

create table test(
    id int,
    test_id int,
    sort int,
    unique(test_id, sort)
);

INSERT INTO `test` (`id`, `test_id`, `sort`)
VALUES
    (1, 1, 0),
    (2, 1, 1),
    (3, 1, 2);

idが3のレコードのsortを1にしたい場合、普通にupdateしようとすると、複合ユニークの制約によりエラーとなってしまう?

しかし、下記のようにSQLを発行すると、値を重複させることなく更新をかけることが可能となる。

UPDATE test SET sort = (sort + 1) WHERE sort >= 1 ORDER BY sort DESC;
UPDATE test SET sort = 1 WHERE id = 3;

sort の値が1以上の値にすべて1をプラスし、空いた1のポジションにidが3のレコードが滑り込んでいるような形である。

最初のupdate文でORDER BY sort DESCを指定しているが、この指定があることで降順にレコードにupdateをかけられる。 ASC で処理をした場合は、もちろん複合ユニークの制約に引っかかってしまい、エラーとなってしまう。

ORDER BY 句が指定されている場合は、指定されている順序で行が更新されます。

https://dev.mysql.com/doc/refman/5.6/ja/update.html

また、これとは別に、特定のtest_idのレコードはすべてdeleteし、sortの値を振り直してinsertし直すといった洗替する方法も考えられる。

最初、バルクアップデート的なものでいけないかなと考え実際にやってみたが、残念ながらユニーク制約にひっかかってしまった。

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