首頁 後端開發 php教程 Yii2中使用join、joinwith多表關聯查詢

Yii2中使用join、joinwith多表關聯查詢

Jan 21, 2017 am 11:36 AM

表結構

現在有客戶表、訂單表、圖書表、作者表,

客戶表Customer (id customer_name)
訂單表Order (id order_name customer_id book_id)
書表(horid book_name idhorhor_id), id author_name)

模型定義

下面是這4個模型的定義,只寫出其中的關聯

Customer

class Customer extends \yii\db\ActiveRecord
{
// 这是获取客户的订单,由上面我们知道这个是一对多的关联,一个客户有多个订单
public function getOrders()
{
// 第一个参数为要关联的子表模型类名,
// 第二个参数指定 通过子表的customer_id,关联主表的id字段
return $this->hasMany(Order::className(), ['customer_id' => 'id']);
}
}
登入後複製

Order

reee reee

hasMany、hasOne使用

Yii2中的表之間的關聯有2種,它們用來指定兩個模型之間的關聯。

一對一:hasMany

一對一:hasOne

回傳結果:這兩個方法的回傳結果都為yiidbActiveQuery物件

第一個參數:所關聯的模型的類別名稱。


第二個參數:是一個數組,其中鍵為所關聯的模型中的屬性,值為目前模型中的屬性。

關聯的使用

現在我們獲取一個客戶的所有的訂單資訊

class Order extends \yii\db\ActiveRecord
{
// 获取订单所属用户
public function getCustomer()
{
//同样第一个参数指定关联的子表模型类名
//
return $this->hasOne(Customer::className(), ['id' => 'customer_id']);
}
// 获取订单中所有图书
public function getBooks()
{
//同样第一个参数指定关联的子表模型类名
//
return $this->hasMany(Book::className(), ['id' => 'book_id']);
}
}
登入後複製

上面的兩行程式碼會產生如下sql語句

class Book extends \yii\db\ActiveRecord
{
// 获取图书的作者
public function getAuthor()
{
//同样第一个参数指定关联的子表模型类名
return $this->hasOne(Author::className(), ['id' => 'author_id']);
}
}
登入後複製

,客戶關聯結果緩存再重新調用

class Autor extends \yii\db\ActiveRecord
{
}
登入後複製

再次得到訂單的時候你會發現沒有變化。原因是只會在第一次執行$customer->orders的時候才會去資料庫裡面查詢,然後會把結果快取起來,以後查詢的時候都不會再執行sql。

那麼如果我想再次執行sql如何做呢?可以執行

// 获取一个客户信息
$customer = Customer::findOne(1);
$orders = $customer->orders; // 通过在Customer中定义的关联方法(getOrders())来获取这个客户的所有的订单。
登入後複製

然後就可以從資料庫裡面取資料了。

定義多重關聯

同樣,我們還可以在Customer裡面定義多個關聯。

如回傳總數大於100的訂單。

SELECT * FROM customer WHERE id=1;
SELECT * FROM order WHERE customer_id=1;
登入後複製

相關的兩種訪問方式

如上面的,如果使用

$orders = $customer->orders;
登入後複製

   


將會得到大於100的所有的訂單。如果要回傳大於200的訂單可以這樣寫

unset($customer->orders);
$customer->orders;
登入後複製

從上面可以看出訪問一個關聯的時候有兩種方法

如果以函數的方式調用,會返回一個ActiveQuery 物件($customer->getOrders ()->all())

如果以屬性的方式調用,會直接返回模型的結果($customer->orders)

with的使用看如下代碼,是取一個客戶的訂單

class Customer extends \yii\db\ActiveRecord
{
public function getBigOrders($threshold = 100)
{
return $this->hasMany(Order::className(), ['customer_id' => 'id'])
->where('subtotal > :threshold', [':threshold' => $threshold])
->orderBy('id');
}
}
登入後複製


如果現在我們要取出100個用戶,然後訪問每個用戶的訂單,從上面的了解我們可能會寫出如下代碼

$customer->bigOrders
登入後複製


然而,如果真要這樣寫的話,會在foreach的每個循環裡面都執行一次sql去資料庫裡面查詢資料。因為每個$customer物件都是不一樣的。

為了解決上面的問題 可以使用 yiidbActiveQuery::with()。

其中width的參數為關係的名稱,也就在model裡面定義的getOrders,getCustomer中的orders和customer

$orders = $customer->getBigOrders(200)->all();
登入後複製

如果使用了select來指定傳回的列,一定要確保傳回的欄位包含所包含所包含的列關聯的模型的關聯字段,否則將不會返回關聯的表的Model

// 执行sql语句: SELECT * FROM customer WHERE id=1
$customer = Customer::findOne(1);
//执行sql:SELECT * FROM order WHERE customer_id=1
$orders1 = $customer->orders;
//这个不会执行sql,直接使用上面的缓存结果
$orders2 = $customer->orders;
登入後複製

給with加過濾條件

查詢一個客戶大於100的訂單

// 执行sql语句: SELECT * FROM customer LIMIT 100
$customers = Customer::find()->limit(100)->all();
foreach ($customers as $customer) {
// 执行sql: SELECT * FROM order WHERE customer_id=...
$orders = $customer->orders;
// 处理订单。。。
}
登入後複製

查詢一個客戶大於100的訂單

// 先执行sql: SELECT * FROM customer LIMIT 100;
// SELECT * FROM orders WHERE customer_id IN (1,2,...)
$customers = Customer::find()->limit(100)
->with('orders')->all();
foreach ($customers as $customer) {
// 在这个循环的时候就不会再执行sql了
$orders = $customer->orders;
// ...handle $orders...
}
登入後複製

查詢100個客戶的的總合大於100的訂單

$orders = Order::find()->select(['id', 'amount'])->with('customer')->all();
// $orders[0]->customer 的结果将会是null
// 因为上面的select中没有返回所关联的模型(customer)中的指定的关联字段。
// 如果加上customer_id,$orders[0]->customer就可以返回正确的结果
$orders = Order::find()->select(['id', 'amount', 'customer_id'])->with('customer')->all();
登入後複製

在這裡width的參數為數組,鍵為關聯的名稱,值為回呼函數。

也就是說對orders這個關聯返回的ActiveQuery,再執行一次$query->andWhere('subtotal>100');

使用joinWith進行表關聯

我們都知道可以用join on來寫多個表之間的關聯。先看看yii2中joinWit的宣告

//首先执行sql: SELECT * FROM customer WHERE id=1
$customer = Customer::findOne(1);
// 再执行查询订单的sql语句:SELECT * FROM order WHERE customer_id=1 AND subtotal>100
$orders = $customer->getOrders()->where('subtotal>100')->all();
登入後複製

$with 資料類型為字串或數組,如果為字串,則為模型中定義的關聯的名稱(可以為子關聯)。

如果為數組,鍵為model中以getXXX格式定義的關聯,值為這個關聯的進一步的回調操作。

$eagerLoading 是否載入在$with中關聯的模型的資料。

$joinType 聯結類型,可用值為:LEFT JOIN、INNER JOIN,預設值為LEFT JOIN

// 下面的代码会执行sql语句:
// SELECT * FROM customer LIMIT 100
// SELECT * FROM order WHERE customer_id IN (1,2,...) AND subtotal>100
$customers = Customer::find()->limit(100)->with([
'orders' => function($query) {
$query->andWhere('subtotal>100');
},
])->all();
登入後複製


在實作上,Yii 先執行滿足JOIN查詢條件的SQL語句,把結果填入主模型中,把結果填入主查詢模型中,然後再為每個關聯執行一條查詢語句, 並填入對應的關聯模型。

joinWith( $with, $eagerLoading = true, $joinType = 'LEFT JOIN' )
登入後複製

On條件

在定義關聯的時候還可以指定on條件

// 订单表和客户表以Left join的方式关联。
// 查找所有订单,并以客户 ID 和订单 ID 排序
$orders = Order::find()->joinWith('customer')->orderBy('customer.id, order.id')->all();
// 订单表和客户表以Inner join的方式关联
// 查找所有的订单和书
$orders = Order::find()->innerJoinWith('books')->all();
// 使用inner join 连接order中的 books关联和customer关联。
// 并对custmer关联再次进行回调过滤:找出24小时内注册客户包含书籍的订单
$orders = Order::find()->innerJoinWith([
'books',
'customer' => function ($query) {
$query->where('customer.created_at > ' . (time() - 24 * 3600));
}
])->all();
// 使用left join连接 books关联,books关联再用left join 连接 author关联
$orders = Order::find()->joinWith('books.author')->all();
登入後複製

在joinWith中使用

// Order和books关联 inner join ,但不获取books关联对应的数据
$orders = Order::find()->innerJoinWith('books', false)->all();
登入後複製

在joinWith中使用

class User extends ActiveRecord
{
public function getBooks()
{
return $this->hasMany(Item::className(), ['owner_id' => 'id'])->onCondition(['category_id' => 1]);
}
}
登入後複製

在joinWith中使用

//先查询主模型(User)的数据, SELECT user.* FROM user LEFT JOIN item ON item.owner_id=user.id AND category_id=1
// 然后再根据关联条件查询相关模型数据SELECT * FROM item WHERE owner_id IN (...) AND category_id=1
// 这两个在查询的过程中都使用了 on条件。
$users = User::find()->joinWith('books')->all();
登入後複製

如果沒有使用joinwith關聯。這時候on條件會作為where 條件。

// SELECT * FROM user WHERE id=10
$user = User::findOne(10);
登入後複製

總結

首先需要在模型中定義好關聯(如getOrders中的Orders為一個關聯)

然後在with或joinWith中使用在模型中定義的關聯。

其中在使用關聯的時候還可以指定回調方法。

再有就是可以給關聯、with、joinWith指定where或on條件


這一部分其實非常多,也有點亂,有些功能沒說完,如三個表關聯、逆關聯等。

最基本的操作也就大體是這些。如果還有哪個地方想了解的,可以回帖交流。 🎜

以上所述是小編給大家介紹的Yii2中多表關聯查詢(join、joinwith)的相關知識,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回覆大家的。在此也非常感謝大家對PHP中文網的支持!

更多Yii2中使用join、joinwith多表關聯查詢相關文章請關注PHP中文網!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

php中的捲曲:如何在REST API中使用PHP捲曲擴展 php中的捲曲:如何在REST API中使用PHP捲曲擴展 Mar 14, 2025 am 11:42 AM

PHP客戶端URL(curl)擴展是開發人員的強大工具,可以與遠程服務器和REST API無縫交互。通過利用Libcurl(備受尊敬的多協議文件傳輸庫),PHP curl促進了有效的執行

在Codecanyon上的12個最佳PHP聊天腳本 在Codecanyon上的12個最佳PHP聊天腳本 Mar 13, 2025 pm 12:08 PM

您是否想為客戶最緊迫的問題提供實時的即時解決方案? 實時聊天使您可以與客戶進行實時對話,並立即解決他們的問題。它允許您為您的自定義提供更快的服務

解釋PHP中晚期靜態結合的概念。 解釋PHP中晚期靜態結合的概念。 Mar 21, 2025 pm 01:33 PM

文章討論了PHP 5.3中介紹的PHP中的晚期靜態結合(LSB),允許靜態方法的運行時間分辨率調用以更靈活的繼承。 LSB的實用應用和潛在的觸摸

在PHP API中說明JSON Web令牌(JWT)及其用例。 在PHP API中說明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

框架安全功能:防止漏洞。 框架安全功能:防止漏洞。 Mar 28, 2025 pm 05:11 PM

文章討論了框架中的基本安全功能,以防止漏洞,包括輸入驗證,身份驗證和常規更新。

自定義/擴展框架:如何添加自定義功能。 自定義/擴展框架:如何添加自定義功能。 Mar 28, 2025 pm 05:12 PM

本文討論了將自定義功能添加到框架上,專注於理解體系結構,識別擴展點以及集成和調試的最佳實踐。

如何用PHP的cURL庫發送包含JSON數據的POST請求? 如何用PHP的cURL庫發送包含JSON數據的POST請求? Apr 01, 2025 pm 03:12 PM

使用PHP的cURL庫發送JSON數據在PHP開發中,經常需要與外部API進行交互,其中一種常見的方式是使用cURL庫發送POST�...

See all articles