查詢構(gòu)建器建立在?Database Access Objects?基礎(chǔ)之上,可讓你創(chuàng)建 程序化的、DBMS無關(guān)的SQL語句。相比于原生的SQL語句,查詢構(gòu)建器可以幫你 寫出可讀性更強(qiáng)的SQL相關(guān)的代碼,并生成安全性更強(qiáng)的SQL語句。
使用查詢構(gòu)建器通常包含以下兩個(gè)步驟:
SELECT
,?FROM
)。all()
)從數(shù)據(jù)庫當(dāng)中檢索數(shù)據(jù)。如下所示代碼是查詢構(gòu)造器的一個(gè)典型用法:
$rows = (new \yii\db\Query())
->select(['id', 'email'])
->from('user')
->where(['last_name' => 'Smith'])
->limit(10)
->all();
上面的代碼將會(huì)生成并執(zhí)行如下的SQL語句,其中?:last_name
?參數(shù)綁定了 字符串?'Smith'
。
SELECT `id`, `email`
FROM `user`
WHERE `last_name` = :last_name
LIMIT 10
提示: 你平時(shí)更多的時(shí)候會(huì)使用 yii\db\Query 而不是 [yii\db\QueryBuilder]]。 當(dāng)你調(diào)用其中一個(gè)查詢方法時(shí),后者將會(huì)被前者隱式的調(diào)用。yii\db\QueryBuilder主要負(fù)責(zé)將 DBMS 不相關(guān)的 yii\db\Query 對(duì)象轉(zhuǎn)換成 DBMS 相關(guān)的 SQL 語句(例如, 以不同的方式引用表或字段名稱)。
為了創(chuàng)建一個(gè) yii\db\Query 對(duì)象,你需要調(diào)用不同的查詢構(gòu)建方法來代表SQL語句的不同子句。 這些方法的名稱集成了在SQL語句相應(yīng)子句中使用的關(guān)鍵字。例如,為了指定 SQL 語句當(dāng)中的?FROM
?子句,你應(yīng)該調(diào)用?from()
?方法。所有的查詢構(gòu)建器方法返回的是查詢對(duì)象本身, 也就是說,你可以把多個(gè)方法的調(diào)用串聯(lián)起來。
接下來,我們會(huì)對(duì)這些查詢構(gòu)建器方法進(jìn)行一一講解:
yii\db\Query::select()
yii\db\Query::select() 方法用來指定 SQL 語句當(dāng)中的?SELECT
?子句。 你可以像下面的例子一樣使用一個(gè)數(shù)組或者字符串來定義需要查詢的字段。當(dāng) SQL 語句 是由查詢對(duì)象生成的時(shí)候,被查詢的字段名稱將會(huì)自動(dòng)的被引號(hào)括起來。
$query->select(['id', 'email']);
// 等同于:
$query->select('id, email');
就像寫原生 SQL 語句一樣,被選取的字段可以包含表前綴,以及/或者字段別名。 例如:
$query->select(['user.id AS user_id', 'email']);
// 等同于:
$query->select('user.id AS user_id, email');
如果使用數(shù)組格式來指定字段,你可以使用數(shù)組的鍵值來表示字段的別名。 例如,上面的代碼可以被重寫為如下形式:
$query->select(['user_id' => 'user.id', 'email']);
如果你在組建查詢時(shí)沒有調(diào)用 yii\db\Query::select() 方法,那么選擇的將是?'*'
?, 也即選取的是所有的字段。
除了字段名稱以外,你還可以選擇數(shù)據(jù)庫的表達(dá)式。當(dāng)你使用到包含逗號(hào)的數(shù)據(jù)庫表達(dá)式的時(shí)候, 你必須使用數(shù)組的格式,以避免自動(dòng)的錯(cuò)誤的引號(hào)添加。例如:
$query->select(["CONCAT(first_name, ' ', last_name) AS full_name", 'email']);
從 2.0.1 的版本開始你就可以使用子查詢了。在定義每一個(gè)子查詢的時(shí)候, 你應(yīng)該使用 yii\db\Query 對(duì)象。例如:
$subQuery = (new Query())->select('COUNT(*)')->from('user');
// SELECT `id`, (SELECT COUNT(*) FROM `user`) AS `count` FROM `post`
$query = (new Query())->select(['id', 'count' => $subQuery])->from('post');
你應(yīng)該調(diào)用 yii\db\Query::distinct() 方法來去除重復(fù)行,如下所示:
// SELECT DISTINCT `user_id` ...
$query->select('user_id')->distinct();
你可以調(diào)用 yii\db\Query::addSelect() 方法來選取附加字段,例如:
$query->select(['id', 'username'])
->addSelect(['email']);
yii\db\Query::from()
yii\db\Query::from() 方法指定了 SQL 語句當(dāng)中的?FROM
?子句。例如:
// SELECT * FROM `user`
$query->from('user');
你可以通過字符串或者數(shù)組的形式來定義被查詢的表名稱。就像你寫原生的 SQL 語句一樣, 表名稱里面可包含數(shù)據(jù)庫前綴,以及/或者表別名。例如:
$query->from(['public.user u', 'public.post p']);
// 等同于:
$query->from('public.user u, public.post p');
如果你使用的是數(shù)組的格式,那么你同樣可以用數(shù)組的鍵值來定義表別名,如下所示:
$query->from(['u' => 'public.user', 'p' => 'public.post']);
除了表名以外,你還可以從子查詢中再次查詢,這里的子查詢是由 yii\db\Query 創(chuàng)建的對(duì)象。 例如:
$subQuery = (new Query())->select('id')->from('user')->where('status=1');
// SELECT * FROM (SELECT `id` FROM `user` WHERE status=1) u
$query->from(['u' => $subQuery]);
yii\db\Query::where()
yii\db\Query::where() 方法定義了 SQL 語句當(dāng)中的?WHERE
?子句。 你可以使用如下三種格式來定義?WHERE
?條件:
'status=1'
['status' => 1, 'type' => 2]
['like', 'name', 'test']
在定義非常簡單的查詢條件的時(shí)候,字符串格式是最合適的。它看起來和原生 SQL 語句差不多。例如:
$query->where('status=1');
// 或者使用參數(shù)綁定來綁定動(dòng)態(tài)參數(shù)值
$query->where('status=:status', [':status' => $status]);
千萬不要像如下的例子一樣直接在條件語句當(dāng)中嵌入變量,特別是當(dāng)這些變量來源于終端用戶輸入的時(shí)候, 因?yàn)檫@樣我們的軟件將很容易受到 SQL 注入的攻擊。
// 危險(xiǎn)!千萬別這樣干,除非你非常的確定 $status 是一個(gè)整型數(shù)值。
$query->where("status=$status");
當(dāng)使用參數(shù)綁定的時(shí)候,你可以調(diào)用 yii\db\Query::params() 或者 yii\db\Query::addParams() 方法 來分別綁定不同的參數(shù)。
$query->where('status=:status')
->addParams([':status' => $status]);
哈希格式最適合用來指定多個(gè)?AND
?串聯(lián)起來的簡單的"等于斷言"子條件。 它是以數(shù)組的形式來書寫的,數(shù)組的鍵表示字段的名稱,而數(shù)組的值則表示 這個(gè)字段需要匹配的值。例如:
// ...WHERE (`status` = 10) AND (`type` IS NULL) AND (`id` IN (4, 8, 15))
$query->where([
'status' => 10,
'type' => null,
'id' => [4, 8, 15],
]);
就像你所看到的一樣,查詢構(gòu)建器非常的智能,能恰當(dāng)?shù)靥幚頂?shù)值當(dāng)中的空值和數(shù)組。
你也可以像下面那樣在子查詢當(dāng)中使用哈希格式:
$userQuery = (new Query())->select('id')->from('user');
// ...WHERE `id` IN (SELECT `id` FROM `user`)
$query->where(['id' => $userQuery]);
操作符格式允許你指定類程序風(fēng)格的任意條件語句,如下所示:
[操作符, 操作數(shù)1, 操作數(shù)2, ...]
其中每個(gè)操作數(shù)可以是字符串格式、哈希格式或者嵌套的操作符格式,而操作符可以是如下列表中的一個(gè):
and
: 操作數(shù)會(huì)被?AND
?關(guān)鍵字串聯(lián)起來。例如,['and', 'id=1', 'id=2']
?將會(huì)生成?id=1 AND id=2
。如果操作數(shù)是一個(gè)數(shù)組,它也會(huì)按上述規(guī)則轉(zhuǎn)換成 字符串。例如,['and', 'type=1', ['or', 'id=1', 'id=2']]
?將會(huì)生成?type=1 AND (id=1 OR id=2)
。 這個(gè)方法不會(huì)自動(dòng)加引號(hào)或者轉(zhuǎn)義。
or
: 用法和?and
?操作符類似,這里就不再贅述。
between
: 第一個(gè)操作數(shù)為字段名稱,第二個(gè)和第三個(gè)操作數(shù)代表的是這個(gè)字段 的取值范圍。例如,['between', 'id', 1, 10]
將會(huì)生成?id BETWEEN 1 AND 10
。
not between
: 用法和?BETWEEN
?操作符類似,這里就不再贅述。
in
: 第一個(gè)操作數(shù)應(yīng)為字段名稱或者 DB 表達(dá)式。第二個(gè)操作符既可以是一個(gè)數(shù)組, 也可以是一個(gè)?Query
?對(duì)象。它會(huì)轉(zhuǎn)換成IN
條件語句。如果第二個(gè)操作數(shù)是一個(gè) 數(shù)組,那么它代表的是字段或 DB 表達(dá)式的取值范圍。如果第二個(gè)操作數(shù)是?Query
?對(duì)象,那么這個(gè)子查詢的結(jié)果集將會(huì)作為第一個(gè)操作符的字段或者 DB 表達(dá)式的取值范圍。 例如,?['in', 'id', [1, 2, 3]]
?將生成?id IN (1, 2, 3)
。 該方法將正確地為字段名加引號(hào)以及為取值范圍轉(zhuǎn)義。in
?操作符還支持組合字段,此時(shí), 操作數(shù)1應(yīng)該是一個(gè)字段名數(shù)組,而操作數(shù)2應(yīng)該是一個(gè)數(shù)組或者?Query
?對(duì)象, 代表這些字段的取值范圍。
not in
: 用法和?in
?操作符類似,這里就不再贅述。
like
: 第一個(gè)操作數(shù)應(yīng)為一個(gè)字段名稱或 DB 表達(dá)式,第二個(gè)操作數(shù)可以使字符串或數(shù)組, 代表第一個(gè)操作數(shù)需要模糊查詢的值。比如,['like', 'name', 'tester']
?會(huì)生成?name LIKE '%tester%'
。 如果范圍值是一個(gè)數(shù)組,那么將會(huì)生成用?AND
?串聯(lián)起來的 多個(gè)?like
?語句。例如,['like', 'name', ['test', 'sample']]
?將會(huì)生成?name LIKE '%test%' AND name LIKE '%sample%'
。 你也可以提供第三個(gè)可選的操作數(shù)來指定應(yīng)該如何轉(zhuǎn)義數(shù)值當(dāng)中的特殊字符。 該操作數(shù)是一個(gè)從需要被轉(zhuǎn)義的特殊字符到轉(zhuǎn)義副本的數(shù)組映射。 如果沒有提供這個(gè)操作數(shù),將會(huì)使用默認(rèn)的轉(zhuǎn)義映射。如果需要禁用轉(zhuǎn)義的功能, 只需要將參數(shù)設(shè)置為?false
?或者傳入一個(gè)空數(shù)組即可。需要注意的是, 當(dāng)使用轉(zhuǎn)義映射(又或者沒有提供第三個(gè)操作數(shù)的時(shí)候),第二個(gè)操作數(shù)的值的前后 將會(huì)被加上百分號(hào)。注意:當(dāng)使用 PostgreSQL 的時(shí)候你還可以使用?
ilike
, > 該方法對(duì)大小寫不敏感。
or like
: 用法和?like
?操作符類似,區(qū)別在于當(dāng)?shù)诙€(gè)操作數(shù)為數(shù)組時(shí), 會(huì)使用?OR
?來串聯(lián)多個(gè)?LIKE
?條件語句。
not like
: 用法和?like
?操作符類似,區(qū)別在于會(huì)使用?NOT LIKE
?來生成條件語句。
or not like
: 用法和?not like
?操作符類似,區(qū)別在于會(huì)使用?OR
?來串聯(lián)多個(gè)?NOT LIKE
?條件語句。
exists
: 需要一個(gè)操作數(shù),該操作數(shù)必須是代表子查詢 yii\db\Query 的一個(gè)實(shí)例, 它將會(huì)構(gòu)建一個(gè)?EXISTS (sub-query)
?表達(dá)式。
not exists
: 用法和?exists
?操作符類似,它將創(chuàng)建一個(gè)?NOT EXISTS (sub-query)
?表達(dá)式。
>
,?<=
, 或者其他包含兩個(gè)操作數(shù)的合法 DB 操作符: 第一個(gè)操作數(shù)必須為字段的名稱, 而第二個(gè)操作數(shù)則應(yīng)為一個(gè)值。例如,['>', 'age', 10]
?將會(huì)生成?age>10
。你可以使用 yii\db\Query::andWhere() 或者 yii\db\Query::orWhere() 在原有條件的基礎(chǔ)上 附加額外的條件。你可以多次調(diào)用這些方法來分別追加不同的條件。 例如,
$status = 10;
$search = 'yii';
$query->where(['status' => $status]);
if (!empty($search)) {
$query->andWhere(['like', 'title', $search]);
}
如果?$search
?不為空,那么將會(huì)生成如下 SQL 語句:
... WHERE (`status` = 10) AND (`title` LIKE '%yii%')
當(dāng)?WHERE
?條件來自于用戶的輸入時(shí),你通常需要忽略用戶輸入的空值。 例如,在一個(gè)可以通過用戶名或者郵箱搜索的表單當(dāng)中,用戶名或者郵箱 輸入框沒有輸入任何東西,這種情況下你想要忽略掉對(duì)應(yīng)的搜索條件, 那么你就可以使用 yii\db\Query::filterWhere() 方法來實(shí)現(xiàn)這個(gè)目的:
// $username 和 $email 來自于用戶的輸入
$query->filterWhere([
'username' => $username,
'email' => $email,
]);
yii\db\Query::filterWhere() 和 yii\db\Query::where() 唯一的不同就在于,前者 將忽略在條件當(dāng)中的hash format的空值。所以如果$email
?為空而?$username
?不為空,那么上面的代碼最終將生產(chǎn)如下 SQL?...WHERE username=:username
。
提示:當(dāng)一個(gè)值為 null、空數(shù)組、空字符串或者一個(gè)只包含空白字符時(shí),那么它將被判定為空值。
類似于 [yii\db\Query::andWhere()|andWhere()]] 和 yii\db\Query::orWhere(), 你可以使用 yii\db\Query::andFilterWhere() 和 yii\db\Query::orFilterWhere() 方法 來追加額外的過濾條件。
yii\db\Query::orderBy()
yii\db\Query::orderBy() 方法是用來指定 SQL 語句當(dāng)中的?ORDER BY
?子句的。例如,
// ... ORDER BY `id` ASC, `name` DESC
$query->orderBy([
'id' => SORT_ASC,
'name' => SORT_DESC,
]);
如上所示,數(shù)組當(dāng)中的鍵指代的是字段名稱,而數(shù)組當(dāng)中的值則表示的是排序的方式。 PHP 的常量?SORT_ASC
?指的是升序排列,SORT_DESC
?指的則是降序排列。
如果?ORDER BY
?僅僅包含簡單的字段名稱,你可以使用字符串來聲明它, 就像寫原生的 SQL 語句一樣。例如,
$query->orderBy('id ASC, name DESC');
注意:當(dāng)?
ORDER BY
?語句包含一些 DB 表達(dá)式的時(shí)候,你應(yīng)該使用數(shù)組的格式。
你可以調(diào)用 [yii\db\Query::addOrderBy()|addOrderBy()]] 來為?ORDER BY
?片斷添加額外的子句。 例如,
$query->orderBy('id ASC')
->addOrderBy('name DESC');
yii\db\Query::groupBy()
yii\db\Query::groupBy() 方法是用來指定 SQL 語句當(dāng)中的?GROUP BY
?片斷的。例如,
// ... GROUP BY `id`, `status`
$query->groupBy(['id', 'status']);
如果?GROUP BY
?僅僅包含簡單的字段名稱,你可以使用字符串來聲明它, 就像寫原生的 SQL 語句一樣。例如,
$query->groupBy('id, status');
注意:當(dāng)?
GROUP BY
?語句包含一些 DB 表達(dá)式的時(shí)候,你應(yīng)該使用數(shù)組的格式。
你可以調(diào)用 [yii\db\Query::addOrderBy()|addOrderBy()]] 來為?GROUP BY
?子句添加額外的字段。例如,
$query->groupBy(['id', 'status'])
->addGroupBy('age');
yii\db\Query::having()
yii\db\Query::having() 方法是用來指定 SQL 語句當(dāng)中的?HAVING
?子句。它帶有一個(gè)條件, 和?where()?中指定條件的方法一樣。例如,
// ... HAVING `status` = 1
$query->having(['status' => 1]);
請(qǐng)查閱?where()?的文檔來獲取更多有關(guān)于如何指定一個(gè)條件的細(xì)節(jié)。
你可以調(diào)用 yii\db\Query::andHaving() 或者 yii\db\Query::orHaving() 方法來為?HAVING
?子句追加額外的條件,例如,
// ... HAVING (`status` = 1) AND (`age` > 30)
$query->having(['status' => 1])
->andHaving(['>', 'age', 30]);
yii\db\Query::limit() 和 yii\db\Query::offset()`
yii\db\Query::limit() 和 yii\db\Query::offset() 是用來指定 SQL 語句當(dāng)中 的?LIMIT
?和?OFFSET
?子句的。例如,
// ... LIMIT 10 OFFSET 20
$query->limit(10)->offset(20);
如果你指定了一個(gè)無效的 limit 或者 offset(例如,一個(gè)負(fù)數(shù)),那么它將會(huì)被忽略掉。
提示:在不支持?
LIMIT
?和?OFFSET
?的 DBMS 中(例如,MSSQL), 查詢構(gòu)建器將生成一條模擬?LIMIT
/OFFSET
?行為的 SQL 語句。
[yii\db\Query::join()|join()]] 是用來指定 SQL 語句當(dāng)中的?JOIN
?子句的。例如,
php
// LEFT JOIN?post
?ON?post
.user_id
?=?user
.id
$query->join('LEFT JOIN', 'post', 'post.user_id = user.id');
yii\db\Query::join() 帶有四個(gè)參數(shù):
* `$type`: 連接類型,例如:`'INNER JOIN'`,?`'LEFT JOIN'`。
* `$table`: 將要連接的表名稱。
* `$on`: 可選參數(shù),連接條件,即?`ON`?子句。請(qǐng)查閱?[where()](http://www.yiichina.com/doc/guide/2.0/db-query-builder#where)?獲取更多有關(guān)于條件定義的細(xì)節(jié)。
* `$params`: 可選參數(shù),與連接條件綁定的參數(shù)。
你可以分別調(diào)用如下的快捷方法來指定?`INNER JOIN`,?`LEFT JOIN`?和?`RIGHT JOIN`。
* yii\db\Query::innerJoin()
* yii\db\Query::leftJoin()
* yii\db\Query::rightJoin()
例如,
$query->leftJoin('post', 'post.user_id = user.id');
可以通過多次調(diào)用如上所述的連接方法來連接多張表,每連接一張表調(diào)用一次。
除了連接表以外,你還可以連接子查詢。方法如下,將需要被連接的子查詢指定 為一個(gè) yii\db\Query 對(duì)象,例如,
$subQuery = (new \yii\db\Query())->from('post');
$query->leftJoin(['u' => $subQuery], 'u.id = author_id');
在這個(gè)例子當(dāng)中,你應(yīng)該將子查詢放到一個(gè)數(shù)組當(dāng)中,而數(shù)組當(dāng)中的鍵,則為這個(gè)子查詢的別名。
yii\db\Query::union()
yii\db\Query::union() 方法是用來指定 SQL 語句當(dāng)中的?`UNION`?子句的。例如,
$query1 = (new \yii\db\Query())
->select("id, category_id AS type, name")
->from('post')
->limit(10);
$query2 = (new \yii\db\Query())
->select('id, type, name')
->from('user')
->limit(10);
$query1->union($query2
~~~);
你可以通過多次調(diào)用 yii\db\Query::union() 方法來追加更多的?UNION
?子句。
yii\db\Query 提供了一整套的用于不同查詢目的的方法。
COUNT
?查詢的結(jié)果。$q
?是一個(gè)必選參數(shù), 既可以是一個(gè)字段名稱,又可以是一個(gè) DB 表達(dá)式。例如,
// SELECT `id`, `email` FROM `user`
$rows = (new \yii\db\Query())
->select(['id', 'email'])
->from('user')
->all();
// SELECT * FROM `user` WHERE `username` LIKE `%test%`
$row = (new \yii\db\Query())
->from('user')
->where(['like', 'username', 'test'])
->one();
注意:yii\db\Query::one() 方法只返回查詢結(jié)果當(dāng)中的第一條數(shù)據(jù), 條件語句中不會(huì)加上?
LIMIT 1
?條件。如果你清楚的知道查詢將會(huì)只返回一行或幾行數(shù)據(jù) (例如, 如果你是通過某些主鍵來查詢的),這很好也提倡這樣做。但是,如果查詢結(jié)果 有機(jī)會(huì)返回大量的數(shù)據(jù)時(shí),那么你應(yīng)該顯示調(diào)用?limit(1)
?方法,以改善性能。 例如,?(new \yii\db\Query())->from('user')->limit(1)->one()
。
所有的這些查詢方法都有一個(gè)可選的參數(shù)?$db
, 該參數(shù)指代的是 yii\db\Connection, 執(zhí)行一個(gè) DB 查詢時(shí)會(huì)用到。如果你省略了這個(gè)參數(shù),那么?db
?application component?將會(huì)被用作 默認(rèn)的 DB 連接。 如下是另外一個(gè)使用?count()
?查詢的例子:
// 執(zhí)行 SQL: SELECT COUNT(*) FROM `user` WHERE `last_name`=:last_name
$count = (new \yii\db\Query())
->from('user')
->where(['last_name' => 'Smith'])
->count();
當(dāng)你調(diào)用 yii\db\Query 當(dāng)中的一個(gè)查詢方法的時(shí)候,實(shí)際上內(nèi)在的運(yùn)作機(jī)制如下:
queryAll()
)來執(zhí)行這條 SQL 語句,并檢索數(shù)據(jù)。有時(shí)候,你也許想要測(cè)試或者使用一個(gè)由 yii\db\Query 對(duì)象創(chuàng)建的 SQL 語句。 你可以使用以下的代碼來達(dá)到目的:
$command = (new \yii\db\Query())
->select(['id', 'email'])
->from('user')
->where(['last_name' => 'Smith'])
->limit(10)
->createCommand();
// 打印 SQL 語句
echo $command->sql;
// 打印被綁定的參數(shù)
print_r($command->params);
// 返回查詢結(jié)果的所有行
$rows = $command->queryAll();
當(dāng)你在調(diào)用 yii\db\Query::all() 方法時(shí),它將返回一個(gè)以連續(xù)的整型數(shù)值為索引的數(shù)組。 而有時(shí)候你可能希望使用一個(gè)特定的字段或者表達(dá)式的值來作為索引結(jié)果集數(shù)組。那么你可以在調(diào)用 yii\db\Query::all() 之前使用 yii\db\Query::indexBy() 方法來達(dá)到這個(gè)目的。 例如,
// 返回 [100 => ['id' => 100, 'username' => '...', ...], 101 => [...], 103 => [...], ...]
$query = (new \yii\db\Query())
->from('user')
->limit(10)
->indexBy('id')
->all();
如需使用表達(dá)式的值做為索引,那么只需要傳遞一個(gè)匿名函數(shù)給 yii\db\Query::indexBy() 方法即可:
$query = (new \yii\db\Query())
->from('user')
->indexBy(function ($row) {
return $row['id'] . $row['username'];
})->all();
該匿名函數(shù)將帶有一個(gè)包含了當(dāng)前行的數(shù)據(jù)的?$row
?參數(shù),并且返回用作當(dāng)前行索引的 標(biāo)量值(譯者注:就是簡單的數(shù)值或者字符串,而不是其他復(fù)雜結(jié)構(gòu),例如數(shù)組)。
當(dāng)需要處理大數(shù)據(jù)的時(shí)候,像 yii\db\Query::all() 這樣的方法就不太合適了, 因?yàn)樗鼈儠?huì)把所有數(shù)據(jù)都讀取到內(nèi)存上。為了保持較低的內(nèi)存需求, Yii 提供了一個(gè) 所謂的批處理查詢的支持。批處理查詢會(huì)利用數(shù)據(jù)游標(biāo)將數(shù)據(jù)以批為單位取出來。
批處理查詢的用法如下:
use yii\db\Query;
$query = (new Query())
->from('user')
->orderBy('id');
foreach ($query->batch() as $users) {
// $users 是一個(gè)包含100條或小于100條用戶表數(shù)據(jù)的數(shù)組
}
// or if you want to iterate the row one by one
foreach ($query->each() as $user) {
// $user 指代的是用戶表當(dāng)中的其中一行數(shù)據(jù)
}
yii\db\Query::batch() 和 yii\db\Query::each() 方法將會(huì)返回一個(gè)實(shí)現(xiàn)了`Iterator`?接口 yii\db\BatchQueryResult 的對(duì)象,可以用在`foreach`?結(jié)構(gòu)當(dāng)中使用。在第一次迭代取數(shù)據(jù)的時(shí)候, 數(shù)據(jù)庫會(huì)執(zhí)行一次 SQL 查詢,然后在剩下的迭代中,將直接從結(jié)果集中批量獲取數(shù)據(jù)。默認(rèn)情況下, 一批的大小為 100,也就意味著一批獲取的數(shù)據(jù)是 100 行。你可以通過給?`batch()`?或者?`each()`?方法的第一個(gè)參數(shù)傳值來改變每批行數(shù)的大小。
相對(duì)于 yii\db\Query::all() 方法,批處理查詢每次只讀取 100 行的數(shù)據(jù)到內(nèi)存。 如果你在處理完這些數(shù)據(jù)后及時(shí)丟棄這些數(shù)據(jù),那么批處理查詢可以很好的幫助降低內(nèi)存的占用率。
如果你通過 yii\db\Query::indexBy() 方法為查詢結(jié)果指定了索引字段,那么批處理查詢將仍然保持相對(duì)應(yīng)的索引方案,例如,
$query = (new \yii\db\Query())
->from('user')
->indexBy('username');
foreach ($query->batch() as $users) {
// $users 的 “username” 字段將會(huì)成為索引
}
foreach ($query->each() as $username => $user) {
}
更多建議: