子モデルの条件を元に親モデルの検索をしたい場合の実装について

217 views
Skip to first unread message

Ryosuke Yoshinari

unread,
Feb 1, 2016, 12:52:23 AM2/1/16
to fuelphp.jp
はじめまして。fuelphpの質問よりも
データベースよりの質問になってしまうかもしれません。

「顧客」を表すモデル

Model_Customer

が存在し、その子モデル「履歴」が関連づけられていて

Model_History

が存在するとします。

class Model_Customer extends Model
{
...

protected static $_has_many = array(
'crammerhistories' => array(
'key_from' => 'id',
'model_to' => 'Model_History',
'key_to' => 'customer_id',
'cascade_save' => true,
'cascade_delete' => false,
)
);
}

class Model_History extends \Orm\Model
{
...

protected static $_belongs_to = array(
'customer' => array(
'key_from' => 'customer_id',
'model_to' => 'Model_Customer',
'key_to' => 'id',
'cascade_save' => true,
'cascade_delete' => false,
)
);
}


という具合です。

Model_Customer は

id(int)
name(varchar[64])

をプロパティに持ち、

Model_History は

id(int)
code(int)
customer_id(int)(外部キー)
applied_at(datetime)

をプロパティに持つとします。

親モデル Model_Customer は、子モデル Model_History に対し、
「現在のコードが何か」というのを、

各々のModel_Customerに対し、外部キー(customer_id)がそのモデルIDと同じになるような
Model_Historyを、applied_at(datetime)順にソートして、「最後に来たもの」
(すなわち、最新の時刻のcode)となるように定義します。

例えば
Model_Customer

 id | name
----+------
  1 | tarou
  2 | jirou

Model_History

 id | code | customer_id | applied_at
----+------+-------------+-----------
  1 | 8    | 1           | 2015/01/21
  2 | 5    | 1           | 2015/02/01
  3 | 7    | 2           | 2015/02/01
  4 | 9    | 2           | 2015/01/21

というテーブルがあったとすると、ここから、

name  | code
------+--------
tarou | 5
jirou | 7

というテーブルを作りたいのです。


なお、条件検索もしたいのです。

すなわち、「現在のcode」が 5番 である顧客一覧を生成したい場合です。



方法としてすぐ思いついたのは、
current_codeというカラム(現在のcodeが何であるか)を
Model_Customerに追加することです。


実際、current_codeというカラムを追加することで、
find の where句で current_code を調べる方法で
実装には成功しました。
(ページネーションも組み合わました)

Model_Customer::find('all',array(
'related' => array('histories'),
'where' =>array(
array('current_code','=',5);
),
'limit' => $pagination->per_page,
'offset' => $pagination->offset,
));


ただしこのような方法ですと、
余分なカラムを追加することになってしまいます。

どうにかカラムを追加することなく、子モデルを調べて計算した値が
親モデルの条件検索に反映されるような実装ができませんでしょうか。


わかりにくい文章で大変すみません。

質問は以上になります。

Ryosuke Yoshinari

unread,
Feb 1, 2016, 1:48:35 AM2/1/16
to fuelphp.jp
crammerhistories
という個所が途中、ありますが、histories の間違いです。
すみません
 

kit.t

unread,
Feb 2, 2016, 3:47:52 AM2/2/16
to fuelphp.jp
kittです。

FuelPHP上では一対多の関係のみで、子テーブルのソート順の指定はできませんので、
列番号を取得できないMySQLではサブクエリになると思います。
そうすると以下のような実装でしょうか。

Model_Customer::find('all',array(
'related' => array('histories'),
'where' =>array(
array('t1.applied_at', '=', 
DB::select(DB::expr('MAX(applied_at)'))
    ->from->(array('histories', 't2'))
   ->where('t1.customer_id', '=', DB::expr('t2.customer_id'))
),
array('t1.code','=',5),

Ryosuke Yoshinari

unread,
Feb 3, 2016, 9:20:56 PM2/3/16
to fuelphp.jp
kittさん ありがとうございます。

教えていただいた実装でもデータがとれました。
大変ありがとうございました。

kit.t

unread,
Feb 4, 2016, 7:29:37 AM2/4/16
to fuelphp.jp
補足です

FuelPHP上では一対多の関係のみで、子テーブルのソート順の指定はできませんので、

この点正確ではありませんでした。


conditionsを利用して自動的に子テーブルのソートが可能でした。
ただし、staticなプロパティのため、今回のようなサブクエリはDB::exprを含むため使えません。

子テーブル側に
最新のデータが1、それ以外は0を持つ
ようなカラムを追加する実装の場合、conditionsによるwhere(実際はon)で、
1対1の関係で自動的に最新レコードをつけることもできます。


Ryosuke Yoshinari

unread,
Feb 7, 2016, 10:45:27 PM2/7/16
to fuelphp.jp
質問のつづきがあります。

id = 3, name = 'saburou' はHistoryを持っていないものとします。

すなわち、データはこのようになります。

 id | name
----+------
  1 | tarou
  2 | jirou
  3 | saburou

Model_History

 id | code | customer_id | applied_at
----+------+-------------+-----------
  1 | 8    | 1           | 2015/01/21
  2 | 5    | 1           | 2015/02/01
  3 | 7    | 2           | 2015/02/01
  4 | 9    | 2           | 2015/01/21

このとき、条件検索にて、現在のcode(最新の日付のcode)
がnullであるような検索もしたいと思っています。

つまり、Historyを持たないsaburouの現在のcodeがnullとなるように定め、
なおかつ、そのような saburou を 最新codeがnullで検索したときにヒットさせる方法です。

おっしゃったやりかたで


Model_Customer::find('all',array(
'related' => array('histories'),
'where' =>array(
array('t1.applied_at', '=', 
DB::select(DB::expr('MAX(applied_at)'))
   ->from->(array('histories', 't2'))
   ->where('t1.customer_id', '=', DB::expr('t2.customer_id'))
),
array('t1.code','IS',null), <-ここをnull値にする
),
..
));

と、そうしますと結果が0件になってしまいます。

単純にそうはいかないようです。

Ryosuke Yoshinari

unread,
Feb 8, 2016, 2:14:59 AM2/8/16
to fuelphp.jp
ありがとうございます。
カラムを追加する方法が実装が簡単になるようなのですね。
Reply all
Reply to author
Forward
0 new messages