特殊なクエリー・コンストラクタの書き込み-(5、集約関数、グループ化、ソート、ページング)
where関連の句の構造が完了したら、他の句を構築し続けます.この記事では,集約関数,パケット,ソートなどの句の構造を行う.
集約関数
SQLには、SUM、COUNT、AVGなどの集約関数と呼ばれる統計、要約のための関数があります.
select()メソッドを使用する場合、select('COUNT(id))という書き方で集約関数を使用することができますが、この方法には欠点があります.意味的には直感的ではない キーワードの競合を防ぐには、手動で引用符を追加する必要があります(3番目の条件クエリーを参照). 集約データを取得するには、 を呼び出す煩雑な方法が必要である.
集約データをより容易に得るためには、単独で作成する方法が必要です.
getList()メソッド
列を取得する方法は、PDO::FETCH_COLUMNで完了します.
ベースクラスgetList()メソッドの追加:
count()メソッド
ベースクラス追加count()メソッド:
構築SQL
集約関数メソッドはget(),row()メソッドと同様に結果をとるため,チェーン呼び出し時に最後に実行することを忘れないでください.
その他の方法
sum()、avg()などの方法ではCOUNT('*')のようなシーンはなく、count()の方法の作成よりも簡単です.
sum()メソッド:
他の方法、例えばavg()、max()などの記述は一つ一つ示されていません.コードはWorkerF-集約関数を参照してください.
グループ:group byとhaving
groupby句は、グループ化するフィールドを1つ以上(カンマで区切られた)指定します.
having句はgroupby句とともに用いられ,パケットのフィルタ条件として空であり,キーワードを除いて文法とwhere句はほぼ同じである.
ベースクラス新規groupBy()メソッド:
ベースクラスにhaving()、orHaving()メソッドを追加します.
ここでは、オリジナル文字列を処理するhavingRaw()メソッド(データバインドを行わずに手動でデータを記入する)も残します.
構築SQL
ツールバーの
並べ替えは簡単です.固定文法と正順、逆順の2つのモードで、複数のフィールドを並べ替えるときにカンマで区切ります.
構築SQL
limitとページング
limit句
標準SQLのlimit句はlimit、offsetキーワードとともに使用されます.Mysqlには
構築SQL
ページング
データリクエスト時にリクエストリソースのデータ量が大きいという問題が発生します.この問題に対して、一般的な解決策はページングです.
limit()メソッドがあれば、ページング機能の実現が可能になります.
柔軟なアクセスのために、次のデータを返します.データの合計 ページあたりのデータ数 現在のページ 次ページ 前ページ 第1ページ 最終ページ 現在のページのデータセット 取得したデータの合計数について、いくつかの問題があります.
合計の取得方法もちろん,上述した集約関数count()を用いて処理する.しかし、count()メソッドを使用するとSQLの構築と実行が1回行われる(実行すると構築文字列が初期状態に設定される)に相当しますが、ページデータセットの取得はどのように行われますか?
2回の実行
もちろん解決策はありますが、2回構築します.
我々のクエリー・コンストラクタ構造は、インスタンスを新規作成するたびにPDOの接続を得るので、2回作成するためにインスタンスを新規作成すると、コストがかかりすぎます.では、1つのインスタンスで2回実行するにはどうすればいいですか.
前編を振り返ると,サブクエリを含むSQL構造は2回の構造を経て,構造文字列を保護・復元した.では、ページングに変更するか、SQLを2回構築するか、構造文字列を保護、復元します.違いは、2回実行するため、バインドされたデータも保護、復元することです.
ベースクラスにバインドデータの保存、復元を追加する方法:
ベースクラスにpaginate()メソッドを追加するには:
テストして、5ページ目のデータを取得します.1ページあたり10個のデータを取得します.
Just do it!
集約関数
SQLには、SUM、COUNT、AVGなどの集約関数と呼ばれる統計、要約のための関数があります.
select()メソッドを使用する場合、select('COUNT(id))という書き方で集約関数を使用することができますが、この方法には欠点があります.
集約データをより容易に得るためには、単独で作成する方法が必要です.
getList()メソッド
列を取得する方法は、PDO::FETCH_COLUMNで完了します.
ベースクラスgetList()メソッドの追加:
public function getList($field)
{
$this->_cols_str = ' '.self::_quote($field).' ';
$this->_buildQuery();
$this->_execute();
//
return $this->_pdoSt->fetchAll(PDO::FETCH_COLUMN, 0);
}
count()メソッド
ベースクラス追加count()メソッド:
public function count($field = '*')
{
// *
// *
if(trim($field) != '*') {
$field = self::_quote($field);
}
//
$this->_cols_str = ' COUNT('.$field.') AS count_num ';
//
return $this->row()['count_num'];
}
構築SQL
SELECT COUNT(id) FROM test_table;
$results = $driver->table('test_table')
->count('id');
集約関数メソッドはget(),row()メソッドと同様に結果をとるため,チェーン呼び出し時に最後に実行することを忘れないでください.
その他の方法
sum()、avg()などの方法ではCOUNT('*')のようなシーンはなく、count()の方法の作成よりも簡単です.
sum()メソッド:
public function sum($field)
{
$this->_cols_str = ' SUM('.self::_quote($field).') AS sum_num ';
return $this->row()['sum_num'];
}
他の方法、例えばavg()、max()などの記述は一つ一つ示されていません.コードはWorkerF-集約関数を参照してください.
グループ:group byとhaving
groupby句は、グループ化するフィールドを1つ以上(カンマで区切られた)指定します.
having句はgroupby句とともに用いられ,パケットのフィルタ条件として空であり,キーワードを除いて文法とwhere句はほぼ同じである.
ベースクラス新規groupBy()メソッド:
public function groupBy($field)
{
// ?
if($this->_groupby_str == '') {
$this->_groupby_str = ' GROUP BY '.self::_wrapRow($field);
} else { // ( ),
$this->_groupby_str .= ' , '.self::_wrapRow($field);
}
return $this;
}
ベースクラスにhaving()、orHaving()メソッドを追加します.
public function having()
{
$operator = 'AND';
// ?
if($this->_having_str == '') {
$this->_having_str = ' HAVING ';
} else {
$this->_having_str .= ' '.$operator.' ';
}
// where
$this->_condition_constructor(func_num_args(), func_get_args(), $this->_having_str);
return $this;
}
public function orHaving()
{
$operator = 'OR';
if($this->_having_str == '') {
$this->_having_str = ' HAVING ';
} else {
$this->_having_str .= ' '.$operator.' ';
}
$this->_condition_constructor(func_num_args(), func_get_args(), $this->_having_str);
return $this;
}
ここでは、オリジナル文字列を処理するhavingRaw()メソッド(データバインドを行わずに手動でデータを記入する)も残します.
public function havingRaw($string)
{
$this->_having_str = ' HAVING '.$string.' ';
return $this;
}
構築SQL
SELECT id, SUM(price) FROM test_table GROUP BY price HAVING SUM(price) > 1000;
:$results = $driver->table('test_table')
->select('id', 'SUM(price)')
->groupBy('price')
->having('SUM(price)', '>', 1000)
->get();
// havingRaw()
$results = $driver->table('test_table')
->select('id', 'SUM(price)')
->groupBy('price')
->havingRaw('SUM(price) > 1000')
->get();
ツールバーの
並べ替えは簡単です.固定文法と正順、逆順の2つのモードで、複数のフィールドを並べ替えるときにカンマで区切ります.
public function orderBy($field, $mode = 'ASC')
{
$mode = strtoupper($mode);
if ( ! in_array($mode, ['ASC', 'DESC'])) {
throw new \InvalidArgumentException("Error order by mode");
}
// ?
if($this->_orderby_str == '') {
$this->_orderby_str = ' ORDER BY '.self::_wrapRow($field).' '.$mode;
} else {
// ,
$this->_orderby_str .= ' , '.self::_wrapRow($field).' '.$mode;
}
return $this;
}
構築SQL
SELECT * FROM tes_table ORDER BY price DESC, id ASC;
:$results = $driver->table('test_table')
->orderBy('price', 'DESC')
->orderBy('id', 'ASC')
->get();
limitとページング
limit句
標準SQLのlimit句はlimit、offsetキーワードとともに使用されます.Mysqlには
LIMIT 0, 10
の略記形式がありますが、PostgreSqlとSqliteは適用されません.limit、offset構文を選択します.public function limit($offset, $step)
{
$this->_limit_str = ' LIMIT '.$step.' OFFSET '.$offset.' ';
return $this;
}
構築SQL
SELECT * FROM test_table LIMIT 10 OFFSET 1;
:$results = $driver->table('test_table')
->limit(1, 10)
->get();
ページング
データリクエスト時にリクエストリソースのデータ量が大きいという問題が発生します.この問題に対して、一般的な解決策はページングです.
limit()メソッドがあれば、ページング機能の実現が可能になります.
柔軟なアクセスのために、次のデータを返します.
合計の取得方法もちろん,上述した集約関数count()を用いて処理する.しかし、count()メソッドを使用するとSQLの構築と実行が1回行われる(実行すると構築文字列が初期状態に設定される)に相当しますが、ページデータセットの取得はどのように行われますか?
2回の実行
もちろん解決策はありますが、2回構築します.
我々のクエリー・コンストラクタ構造は、インスタンスを新規作成するたびにPDOの接続を得るので、2回作成するためにインスタンスを新規作成すると、コストがかかりすぎます.では、1つのインスタンスで2回実行するにはどうすればいいですか.
前編を振り返ると,サブクエリを含むSQL構造は2回の構造を経て,構造文字列を保護・復元した.では、ページングに変更するか、SQLを2回構築するか、構造文字列を保護、復元します.違いは、2回実行するため、バインドされたデータも保護、復元することです.
ベースクラスにバインドデータの保存、復元を追加する方法:
//
protected function _storeBindParam()
{
return $this->_bind_params;
}
//
protected function _reStoreBindParam($bind_params)
{
$this->_bind_params = $bind_params;
}
ベースクラスにpaginate()メソッドを追加するには:
public function paginate($step, $page = NULL)
{
//
$store = $this->_storeBuildAttr();
$bind_params = $this->_storeBindParam();
//
$count = $this->count();
//
$this->_reStoreBuildAttr($store);
$this->_reStoreBindParam($bind_params);
//
$page = $page ? $page : 1; //
$this->limit($step * ($page - 1), $step);
$rst['total'] = $count;
$rst['per_page'] = $step;
$rst['current_page'] = $page;
$rst['next_page'] = ($page + 1) > ($count / $step) ? NULL : ($page + 1);
$rst['prev_page'] = ($page - 1) < 1 ? NULL : ($page - 1);
$rst['first_page'] = 1;
$rst['last_page'] = $count / $step;
$rst['data'] = $this->get();
//
return $rst;
}
テストして、5ページ目のデータを取得します.1ページあたり10個のデータを取得します.
$results = $driver->table('test_table')
->paginate(10, 5);
Just do it!