ホームページ バックエンド開発 PHPチュートリアル Yii2 でのマルチテーブル関連付けクエリでの join と joinwith の使用について

Yii2 でのマルチテーブル関連付けクエリでの join と joinwith の使用について

Jun 19, 2018 am 11:39 AM
join

この記事は、Yii2 のマルチテーブル関連のクエリ (join、joinwith) に関する情報を中心に紹介しています。非常に優れており、必要な方は参考にしてください。

テーブル構造

customer テーブル、order テーブル、book テーブル、author テーブル、

Customer テーブル Customer (id customer_name)
Order テーブル Order (id order_name customer_id book_id)
書籍テーブル(id book_name author_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']);
}
}
ログイン後にコピー

注文

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']);
}
}
ログイン後にコピー

予約

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

Author

class Autor extends \yii\db\ActiveRecord
{
}
ログイン後にコピー

hasMany、hasOne は のテーブルを使用します

Yii2 2 つのタイプの関連付けがあり、2 つのモデル間の関連付けを指定するために使用されます。

1 対多: hasMany


1 対 1: hasOne


戻り結果: これら 2 つのメソッドの戻り結果は次のとおりです。 \db\ ActiveQuery オブジェクト

最初のパラメータ: 関連付けられたモデルのクラス名。

2 番目のパラメーター: は配列であり、キーは関連付けられたモデルの属性、値は現在のモデルの属性です。

関連使用

顧客のすべての注文情報を取得しました

// 获取一个客户信息
$customer = Customer::findOne(1);
$orders = $customer->orders; // 通过在Customer中定义的关联方法(getOrders())来获取这个客户的所有的订单。
ログイン後にコピー

上記の 2 行のコードにより、次の SQL ステートメントが生成されます。

##
SELECT * FROM customer WHERE id=1;
SELECT * FROM order WHERE customer_id=1;
ログイン後にコピー

#関連する結果キャッシュ

顧客の注文が変更になった場合は、再度電話します

$orders = $customer->orders;
ログイン後にコピー

再度注文を受け取ると、注文が入っていないことがわかります。変化。その理由は、$customer->orders が初めて実行されるときにのみデータベースがクエリされ、その結果がキャッシュされ、後続のクエリでは SQL が実行されないためです。

それでは、SQL を再度実行したい場合はどうすればよいでしょうか?

unset($customer->orders);
$customer->orders;
ログイン後にコピー

を実行すると、データベースからデータを取得できます。

複数の関連付けの定義

同様に、Customer で複数の関連付けを定義することもできます。 返される注文の合計数が 100 を超える場合。


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');
}
}
ログイン後にコピー

関連する 2 つのアクセス方法

上記と同様、使用する場合は

$customer->bigOrders
ログイン後にコピー

は、100 を超えるすべての注文を取得します。 200 を超える注文を返したい場合は、次のように記述できます。

$orders = $customer->getBigOrders(200)->all();
ログイン後にコピー

上記からわかるように、関連付けにアクセスするには 2 つの方法があります。

関数として呼び出された場合、ActiveQuery オブジェクト ($customer->getOrders()->all()) が返されます。 ($customer->orders)

の結果は、顧客の注文を取得するための次のコードを示します。
// 执行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;
ログイン後にコピー


ここで 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;
// 处理订单。。。
}
ログイン後にコピー
## を作成できます。

# ただし、本当に必要な場合は、このように記述すると、foreach の各ループで SQL が 1 回実行され、データベース内のデータがクエリされます。 $customer オブジェクトはそれぞれ異なるためです。

上記の問題を解決するには、yii\db\ActiveQuery::with() を使用できます。

width パラメーターはリレーションシップの名前です。これは、モデルで定義された getOrders、getCustomer の注文および顧客です。

// 先执行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...
}
ログイン後にコピー

Select を使用して返される列を指定する場合は、返される列に関連モデルの関連フィールドが含まれていることを確認してください。そうでない場合は、関連テーブルの Model

$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();
ログイン後にコピー

## が返されます。

#with

100 人を超える顧客の注文をクエリする

//首先执行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();
ログイン後にコピー

100 人の顧客をクエリします。各顧客の注文合計は 100 を超えます。

// 下面的代码会执行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();
ログイン後にコピー

ここでの width パラメータは配列であり、キーは関連付けられた名前、値はコールバック関数です。

つまり、注文関連付けから返された ActiveQuery に対して、$query->andWhere('subtotal>100');

joinWith を使用して、テーブル処理の実行 Association

join on を使用して複数のテーブル間の関連付けを書き込むことができることは誰もが知っています。まず、yii2

joinWith( $with, $eagerLoading = true, $joinType = 'LEFT JOIN' )
ログイン後にコピー

$with の joinWit の宣言を見てください。データ型は文字列または配列です。文字列の場合、それは関連付けです。モデルで定義された名前 (子関連付けも可能)。 配列の場合、キーはモデル内の getXXX 形式で定義された関連付けであり、値はこの関連付けに対するさらなるコールバック操作です。

$eagerLoading $with に関連付けられたモデルのデータをロードするかどうか。

$joinType 联接类型,可用值为:LEFT JOIN、INNER JOIN,默认值为LEFT JOIN

// 订单表和客户表以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();
ログイン後にコピー

在实现上,Yii 先执行满足JOIN查询条件的SQL语句,把结果填充到主模型中, 然后再为每个关联执行一条查询语句, 并填充相应的关联模型。

// Order和books关联 inner join ,但不获取books关联对应的数据
$orders = Order::find()->innerJoinWith('books', false)->all();
ログイン後にコピー

On条件

在定义关联的时候还可以指定on条件

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();
ログイン後にコピー

如果没有使用join操作,即使用的是with 或者 直接以属性来访问关联。这个时候on条件会作为where 条件。

// SELECT * FROM user WHERE id=10
$user = User::findOne(10);
ログイン後にコピー

总结

首先需要在模型中定义好关联(如getOrders中的Orders为一个关联)

然后在with或者joinWith中使用在模型中定义的关联。

其中在使用关联的时候还可以指定回调方法。

再有就是可以给关联、with、joinWith指定where或者on条件

这一部分其实非常多,也有点乱,有些功能没说说完,如三个表关联、逆关联等。

最基本的操作也就大体是这些。如果还有哪个地方想了解的,可以回帖交流。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

关于Yii实现的多级联动下拉菜单

Yii中表单用法实例

关于YII关联查询的解析

以上がYii2 でのマルチテーブル関連付けクエリでの join と joinwith の使用についての詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

MySQLでJOINを使用する方法 MySQLでJOINを使用する方法 Jun 04, 2023 am 08:02 AM

JOIN の意味は英語の「結合」と同じで、2 つのテーブルを結合するもので、内部結合、外部結合、右結合、左結合、自然結合に大別されます。まず 2 つのテーブルを作成します。例として次のものが使用されます。 CREATETABLEt_blog(idINTPRIMARYKEYAUTO_INCREMENT,titleVARCHAR(50),typeIdINT);SELECT*FROMt_blog;+----+------+--------+ | id|title|typeId|+----+----------+--------+|1|aaa|1||2|bbb|2||3|ccc|3 |

MySQL Join の使用原理は何ですか? MySQL Join の使用原理は何ですか? May 26, 2023 am 10:07 AM

結合タイプ leftjoin は、左側のテーブルを駆動テーブルとして使用し、左側のテーブルを結果セットの基礎として使用します。右側のテーブルのデータは結果セットに接続されます。rightjoin は、右側のテーブルを駆動テーブルとして使用し、右側のテーブルを結果セットとして使用します。左側のテーブルを接続するための結果セットの基礎 データは結果セットの innerjoin に追加されます 結果セットは 2 つのテーブルの共通部分を取得します fulljoin 結果セットは 2 つのテーブルの結合を取得します MySQL にはfulljoin。union と Unionall の違いは、union がクロスジョインのデカルト積の重複を排除することです。where 条件が使用されていない場合、結果セットは、関連付けられた 2 つのテーブル行の積になります。違いは、クロスジョインが結果を作成するときの点です。設定されている場合は、on 条件に従って渡されます。

mysqlの結合クエリと複数のクエリ方法とは何ですか? mysqlの結合クエリと複数のクエリ方法とは何ですか? Jun 02, 2023 pm 04:29 PM

結合クエリと複数のクエリを比較すると、MySQL の複数テーブル関連のクエリと複数の単一テーブルのクエリのどちらが効率的ですか?データの量が十分に大きくない場合、結合を使用しても問題ありませんが、通常はサービス層で実行されます。第一に、スタンドアロン データベースのコンピューティング リソースは非常に高価であり、データベースは書き込みと書き込みの両方に対応する必要があります。データベースを作成するために、スループットが高くなり、数百マイクロ秒からミリ秒の遅延ギャップを気にする必要がなくなり、ビジネスはより多くの計算をサービス層に投入するようになります。結局のところ、コンピューティングリソースは水平拡張が容易で、データベースは難しいので、ほとんどのビジネスは純粋なコンピューティング操作をサービス層に置き、データベースをトランザクション機能を備えたkvシステムとして使用する重いビジネスです。

MySQLでJOINを使用する方法 MySQLでJOINを使用する方法 Jun 03, 2023 am 09:30 AM

はじめに A のユニーク + AB のパブリック B のユニーク + AB のパブリック AB のパブリック A のユニーク B のユニーク A のユニーク + B のユニーク + AB のパブリック A のユニーク + B のユニーク テーブル部門テーブルの作成の練習 DROPTABLEIFEXISTS`dept`;CREATETABLE`dept`(`dept_id`int( 11)NOTNULLAUTO_INCREMENT,`dept_name`varchar(30)DEFAULTNULL,`dept_number`int(11)DEFAULTNULL,PRIMARYKEY(`dept_id`))ENGINE =InnoDBAUT

MySQL の JOIN 関数を使用してテーブルを結合する MySQL の JOIN 関数を使用してテーブルを結合する Jul 26, 2023 am 08:37 AM

MySQL の JOIN 関数を使用してテーブルを結合する MySQL では、JOIN は非常に一般的な操作であり、テーブル間に関連付けられたフィールドに基づいて 2 つ以上のテーブルを結合できます。これにより、クエリを実行して複数のテーブルから関連データを取得することが容易になり、クエリの効率と柔軟性が向上します。この記事では、コード例を使用して、MySQL の JOIN 関数を使用してテーブルを結合する方法を示します。まず、学生とスコアの 2 つのサンプル テーブルを作成します。学生テーブルには学生が含まれています

MySQL の JOIN 最適化を通じてパフォーマンスを向上させる方法 MySQL の JOIN 最適化を通じてパフォーマンスを向上させる方法 May 11, 2023 am 08:48 AM

ほとんどの Web アプリケーションでは、データベース操作が最も基本的かつ重要な部分です。現在、最も一般的に使用されているリレーショナル データベース管理システムとして、MySQL は無数の Web サイトとアプリケーションをホストしていますが、大規模なデータ処理とクエリ アクセスに対するプレッシャーも増大しています。この文脈において、パフォーマンスの最適化は MySQL データベース管理の重要な部分となっており、JOIN 操作が重要なポイントとなります。 JOIN 接続は、MySQL で最も一般的に使用されるデータ クエリ ステートメントの 1 つです。存在する

MySQL で join ステートメントを最適化する方法 MySQL で join ステートメントを最適化する方法 Jun 03, 2023 am 09:31 AM

SimpleNested-LoopJoin 結合操作を実行するときに mysql がどのように動作するかを見てみましょう。一般的な結合方法は何ですか?図に示すように、接続操作を実行すると、左側のテーブルが駆動テーブル、右側のテーブルが駆動テーブルになります。次に、駆動テーブルのレコードを 1 つずつ照合し、条件に一致する場合は結果を返します。次に、ドライバー テーブル内のすべてのデータが一致するまで、ドライバー テーブル内の次のレコードが照合対象となります。毎回ドライバー テーブルからデータを取得するのは時間がかかるため、MySQL はこのアルゴリズムを使用して接続操作を実行しません。 BlockNested-LoopJ

PHPのjoin()関数を使用して配列を文字列に変換します PHPのjoin()関数を使用して配列を文字列に変換します Jun 26, 2023 pm 11:18 PM

PHP は一般的に使用されるサーバーサイド スクリプト言語であり、多くの便利な関数があり、その 1 つが join() 関数です。配列を文字列に変換できます。この記事では、PHPjoin() 関数を使用して配列を文字列に変換する方法について詳しく説明します。 1. PHPjoin() 関数とは何ですか? join() 関数は、implode() 関数とも呼ばれ、配列を文字列に変換する PHP のメソッドの 1 つです。その機能は、配列内の要素を接続して文字列を形成することです。

See all articles