Baby step - 思考と実験の足跡

日常のちょっとした、気になって試したこと集です。

カラム名に予約語を含むモデルのクエリービルダーを作る

概要

  • あるモデルのカラム名orderのような予約語の場合、クエリービルダー生成時にMySQLのエラーが起きる
  • app.php.env中のquoteIdentifierstrueにすることでエスケープできるが、一部のクエリが書けなくなる
  • クエリービルダー経由でも意外と簡単に書ける

設定ファイルでの対応

以下2ファイルのquoteIdentifiersfalseからtrueに変えた (app.phpだけでいいのかも)

# .env

# Uncomment these to define database configuration via environment variables.
#export DATABASE_URL="mysql://my_app:secret@localhost/${APP_NAME}?encoding=utf8&timezone=UTC&cacheMetadata=true&quoteIdentifiers=true&persistent=false"
#export DATABASE_TEST_URL="mysql://my_app:secret@localhost/test_${APP_NAME}?encoding=utf8&timezone=UTC&cacheMetadata=true&quoteIdentifiers=true&persistent=false"

# app.php
            /**
             * Set identifier quoting to true if you are using reserved words or
             * special characters in your table or column names. Enabling this
             * setting will result in queries built using the Query Builder having
             * identifiers quoted when creating SQL. It should be noted that this
             * decreases performance because each query needs to be traversed and
             * manipulated before being executed.
             */
            'quoteIdentifiers' => true,

これでエラーは解消される。

が、以下のようなクエリーは発行できなくなる。

$query = $this->find(); # $thisはモデル
$query
    ->select([
        'girl_id' => 'CASE TableItems.item_type WHEN 2 THEN TableItemBacks.girl_id ELSE TableItems.girl_id END',
# 中略
    ])

quoteIdentifiers=falseだとSQLを展開してくれるんだけど、 trueだとCASE句がまるまるエスケープされてエラーに...。

クエリービルダーでの対応

こんな感じでクエリを作る。 予約語エスケープするためにバッククオートを付ける

$query = $this->query();
$query->insert(['id', '`order`']); # 予約語のorderに``を付けた
$query->values(['id' => 1, 'order' => 1]);        
$query->execute(); 

# 発行SQL
'INSERT INTO target_tables (id, `order`) VALUES (:c0, :c1)'