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

瀏覽次數:265 次
跳到第一則未讀訊息

Ryosuke Yoshinari

未讀,
2016年2月1日 凌晨12:52:232016/2/1
收件者: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

未讀,
2016年2月1日 凌晨1:48:352016/2/1
收件者:fuelphp.jp
crammerhistories
という個所が途中、ありますが、histories の間違いです。
すみません
 

kit.t

未讀,
2016年2月2日 凌晨3:47:522016/2/2
收件者: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

未讀,
2016年2月3日 晚上9:20:562016/2/3
收件者:fuelphp.jp
kittさん ありがとうございます。

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

kit.t

未讀,
2016年2月4日 清晨7:29:372016/2/4
收件者:fuelphp.jp
補足です

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

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


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

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


Ryosuke Yoshinari

未讀,
2016年2月7日 晚上10:45:272016/2/7
收件者: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

未讀,
2016年2月8日 凌晨2:14:592016/2/8
收件者:fuelphp.jp
ありがとうございます。
カラムを追加する方法が実装が簡単になるようなのですね。
回覆所有人
回覆作者
轉寄
0 則新訊息