質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Doctrine

Doctrineは、データベースの抽象性とPHPで書かれたORMを扱うためのオープンソースのライブラリとツールの集合です。

Doctrine2

Doctrine 2.0はPHP(5.3.2+)のORMです。Doctrine1.2はActive Recordのパターンを使っているのに対し、Doctrine 2はData Mapperパターンを使います。Doctrineのプロジェクトはデータベースの抽象性とPHPで書かれたORMを扱うためのオープンソースのライブラリとツールの集合です。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Symfony

Symfony はPHPで記述されたWebアプリケーションフレームワークです。よく利用するコーディングをテンプレーティングするなど、Webアプリケーション開発の効率化を目的として設計されています。

EC-CUBE

EC-CUBEは、主に日本国内で開発されているECコンテンツ管理システムです。ロックオン社のECKitを元にしてオープンソース化され、商品管理・受注管理・顧客管理・売上集計などECに特化した様々な機能を備えています。

Q&A

2回答

3988閲覧

DoctrineのQueryBuilder、DQLの書き方が分かりません

Mr_sandbox

総合スコア1

Doctrine

Doctrineは、データベースの抽象性とPHPで書かれたORMを扱うためのオープンソースのライブラリとツールの集合です。

Doctrine2

Doctrine 2.0はPHP(5.3.2+)のORMです。Doctrine1.2はActive Recordのパターンを使っているのに対し、Doctrine 2はData Mapperパターンを使います。Doctrineのプロジェクトはデータベースの抽象性とPHPで書かれたORMを扱うためのオープンソースのライブラリとツールの集合です。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Symfony

Symfony はPHPで記述されたWebアプリケーションフレームワークです。よく利用するコーディングをテンプレーティングするなど、Webアプリケーション開発の効率化を目的として設計されています。

EC-CUBE

EC-CUBEは、主に日本国内で開発されているECコンテンツ管理システムです。ロックオン社のECKitを元にしてオープンソース化され、商品管理・受注管理・顧客管理・売上集計などECに特化した様々な機能を備えています。

0グッド

0クリップ

投稿2021/09/17 03:53

Doctrineのsubquery文やjoinを使ったQueryBuilder、DQLの書き方が分かりません
SQL文だと簡単に書けるものが、DoctrineのqueryBuilderやDQLだとどうしても書けなくて2日も悩んでおります。
dtb_customerとdtb_orderがOneToManyの関係にあって、dtb_customer.id = dtb_order.customer_idになっております。
やりたいことは顧客検索欄で購入件数の範囲指定できるようにすることです。
イメージ説明
これをSQLで書くと以下になります。

SQL

1-- subqueryを使った場合 2select * FROM onestopinnov_sid.dtb_customer as c where c.id IN ( 3 select customer_id from onestopinnov_sid.dtb_order group by customer_id, order_status_id having count(customer_id) > 0 AND order_status_id IN ([購入完了ステータスIDをここに]) 4); 5-- joinを使った場合 6select c.id FROM onestopinnov_sid.dtb_customer as c 7 join (select customer_id from onestopinnov_sid.dtb_order group by customer_id, order_status_id having count(customer_id) > 0 AND order_status_id IN ([購入完了ステータスIDをここに])) as o 8 ON c.id = o.customer_id 9 where 10 c.id = o.customer_id 11;

(order_status_idは購入が完了してある注文だけを抽出するためのものです。)

でもこれをquerybuilderで作ろうとするとどうしてもうまくいきません。。。

PHP

1$qb = $this->createQueryBuilder('c') 2 ->select('c'); 3[中略] 4// buy_times 5if (isset($searchData['buy_times_start']) && StringUtil::isNotBlank($searchData['buy_times_start'])) { 6 $qb 7 ->leftJoin('c.Orders', 'o') 8 ->andWhere('COUNT(o.Customer) >= :buy_times_start') 9 ->setParameter('buy_times_start', $searchData['buy_times_start']); 10}

あとDQLでサブクエリを使ってやってみようともしたのですが、これもうまくいきません、、、
(気になる方いらっしゃいましたら書いて失敗したDQLも貼ります)

下記がエラー文です。

bash

1["An exception occurred while executing 'SELECT count(DISTINCT d0_.id) AS sclr_0 FROM dtb_customer d0_ LEFT JOIN dtb_order d1_ ON d0_.id = d1_.customer_id AND d1_.discriminator_type IN ('order') WHERE (COUNT(d1_.customer_id) >= ? AND d0_.customer_status_id IN (?, ?) AND d0_.cognito_flg IN (?, ?) AND d0_.singup_point_flg IN (?, ?)) AND d0_.discriminator_type IN ('customer')' with params [1, 1, 2, true, false, true, false]

以下が二つのEntityの該当のプロパティです。

CustomerのEntity

PHP

1/** 2* @var \Doctrine\Common\Collections\Collection 3* 4* @ORM\OneToMany(targetEntity="Eccube\Entity\Order", mappedBy="Customer") 5*/ 6private $Orders;

OrderのEntity

PHP

1/** 2* @var \Eccube\Entity\Customer 3* 4* @ORM\ManyToOne(targetEntity="Eccube\Entity\Customer", inversedBy="Orders") 5* @ORM\JoinColumns({ 6* @ORM\JoinColumn(name="customer_id", referencedColumnName="id") 7* }) 8*/ 9private $Customer;

ちなみにdtb_customerテーブルには実はbuy_times_startbuy_times_endとかlast_buy_startlast_buy_endなどののカラムが既にあります。
でもこれだと注文に何か更新があるたびにdtb_customerも直さなければいけなくて、なるべくやりたい方法ではないのです。
この考え方はおかしいのでしょうか?
できれば検索の時だけ二つのテーブルをうまく結合したやり方でやりたいのですが、Doctrineの書き方がどうしても分からなくてみなさんの知恵をお借りしたいのです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

手元で試せてはいませんが、以下の方法でいかがでしょうか?

サブクエリ

php

1 $subQuery = $this->_em->createQueryBuilder() 2 ->select('customer_id') 3 ->from(Order::class, 'o') 4 ->groupBy('o.customer_id', 'o.order_status_id') 5 ->having('COUNT(o.customer_id) > 0') 6 ->andHaving('o.order_status_id IN (:orderStatusId)') 7 ->setParameter('orderStatusId', []) 8 ->getDQL() 9 ; 10 11 return $this->createQueryBuilder('c') 12 ->where(sprintf('c.id IN (%s)', $subQuery)) 13 ->getQuery() 14 ->getResult() 15 ;

結合

php

1 2 $subQuery = $this->_em->createQueryBuilder() 3 ->select('customer_id') 4 ->from(Order::class, 'o') 5 ->groupBy('o.customer_id', 'o.order_status_id') 6 ->having('COUNT(o.customer_id) > 0') 7 ->andHaving('o.order_status_id IN (:orderStatusId)') 8 ->setParameter('orderStatusId', []) 9 ->getQuery() 10 ->getSQL() 11 ; 12 13 return $this->createQueryBuilder('c') 14 ->leftJoin(sprintf('(%s)', $subQuery), 'o', 'WITH', 'c.id = 0.customer_id') 15 ->getQuery() 16 ->getResult() 17 ;

投稿2021/11/09 11:19

ggg-mzkr

総合スコア38

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

無理にできないことをやる必要も個人的には無いと思います。

そこまでSQLが直接かけているのであれば、dtb_customer.idを取得するクエリは直接実行し、
idの方はfindByで検索すればいいのではないのでしょうか?

ちなみにSQLを直接実行するには
$stmt = $this->entitiManger->getConnection()->prepare($sql);
でステートメントを取得し、残りはPDOみたいにbindValueやexecute、fetchAllすればいいです。

あとはfetchAllしたidをfindByすれば、お望みのことはできるのではないかと推測します。

投稿2021/09/17 05:29

Ruizi_Luigi

総合スコア208

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問