{"id":617,"date":"2020-06-21T17:41:11","date_gmt":"2020-06-21T15:41:11","guid":{"rendered":"https:\/\/www.mher.de\/?p=617"},"modified":"2024-08-15T16:45:13","modified_gmt":"2024-08-15T14:45:13","slug":"howto-symfony-doctrine-subquery-exists","status":"publish","type":"post","link":"https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/","title":{"rendered":"Howto: Symfony doctrine subquery exists"},"content":{"rendered":"\n<p>In SQL Subqueries are pretty common: you need only those records where a certain condition is dependend on the existance or non-existance of records in an associated table.<br>I.e. you want to delete all shoppingbaskets in the database, which are older than, let&#8217;s say 7 days but only if they do not have any items in them&#8230;<\/p>\n\n\n\n<p>In pure SQL you would write something like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>DELETE \nFROM shopping_basket s \nWHERE s.last_updated &lt; DATE_SUB(NOW(), INTERVAL 7 DAY) \nAND WHERE NOT EXISTS (\n    SELECT * \n    FROM shopping_basket_item i \n    WHERE i.shopping_basket_id = s.id\n)<\/code><\/pre>\n\n\n\n<p>But how would you do that in a Symfony Repository method?<\/p>\n\n\n\n<p>Well, actually it&#8217;s pretty simple, and yet a bit tricky.<\/p>\n\n\n\n<p>The main part (the DELETE) is easy: say, we&#8217;re in the <code>ShoppingBasketRepository <\/code>and create a method &#8220;<code>deleteAllAbandonedAndEmpty<\/code>&#8220;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public function deleteAllAbandonedAndEmpty()\n{\n    return $this-&gt;createQueryBuilder('s')\n        -&gt;delete()\n        -&gt;andWhere('lastUpdated &lt; :sevendaysago)\n        -&gt;setParameter('sevendaysago', new \\DateTime('-7 days'))\n        -&gt;andWhere(\/* hmm here the subquery - but how? *\/)\n        -&gt;getQuery()\n        -&gt;getResult()\n    ;\n}<\/code><\/pre>\n\n\n\n<p>Well, you have to create another QueryBuilder for the subquery and insert its DQL as an expression in the 2nd andWhere clause.<br>And here it becomes a bit tricky, as a simple <code>$this-&gt;createQueryBuilder('x')<\/code> doesn&#8217;t do the trick. <\/p>\n\n\n\n<p>Why? Because this always includes the current Entity with <code>'x'<\/code> as it&#8217;s alias also into that subquery.<\/p>\n\n\n\n<p>But here comes the Repositories internal entity manager to help.<\/p>\n\n\n\n<p>As <code>$this-&gt;createQueryBuilder('x')<\/code> is actually a shortcut and resolves to<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$this-&gt;_em-&gt;createQueryBuilder()\n     -&gt;select($alias) \/\/ alias being the 'x' passed from $this-&gt;createQueryBuilder\n     -&gt;from($this-&gt;_entityName, $alias);<\/code><\/pre>\n\n\n\n<p>But in our subquery we want to set the from ourselves, so we simply have to avoid the shortcut and  build it &#8220;from scratch&#8221; \ud83d\ude09 &#8211; But what exactly do we have to put in instead of $this-&gt;_entityName? To be honest, here PHPStorm came to my help, and after I startet typing the classname, suggested the correct syntax to me: <code>App:ShoppingBasketItem<\/code> &#8211; (what exactly depends on your namespace for the Entities).<br>So our subquery-builder would look something like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$sqb = $this-&gt;_em-&gt;createQueryBuilder()\n     -&gt;select('i')\n     -&gt;from('App:ShoppingBasketItem', 'i')\n     -&gt;andWhere('i.shoppingBasket = \/* hmm, what exactly? *\/')\n;<\/code><\/pre>\n\n\n\n<p>Yes, next big question, in the original SQL we simply compared the shopping_basket_id from the shopping_basket_item table with the id from the shopping_basket table, but in the doctrine QueryBuilder we don&#8217;t handle the ids explicitly, we rather handle objects. So in this case it&#8217;s actually  rather simple: we use the alias of the parent table (um, Entity \ud83d\ude09 ): <code>'s'<\/code><\/p>\n\n\n\n<p>So this is the complete method. Note, that we first had to finish the assignment of the <code>$qb<\/code> variable before we can use it again for the <code>-&gt;expr<\/code> calls!<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public function deleteAllAbandonedAndEmpty()\n{\n    $sqb = $this-&gt;_em-&gt;createQueryBuilder()\n        -&gt;select('i')\n        -&gt;from('App:ShoppingBasketItem', 'i')\n        -&gt;andWhere('i.shoppingBasket = s')\n    ;\n\n    $qb = $this-&gt;createQueryBuilder('s')\n        -&gt;delete()\n        -&gt;andWhere('lastUpdated &lt; :sevendaysago)\n        -&gt;setParameter('sevendaysago', new \\DateTime('-7 days'))\n    ;\n    $qb \n        -&gt;andWhere(\n            $qb-&gt;expr()-&gt;not(\n                $qb-&gt;expr()-&gt;exists(\n                    $sqb-&gt;getDQL()\n                )\n            )\n        )\n   ;\n\n   return $qb\n        -&gt;getQuery()\n        -&gt;getResult()\n    ;\n}<\/code><\/pre>\n\n\n\n<p>I hope you get the idea and can adopt it to your requirements &#8211; and please don&#8217;t start an argument about <code>DATE_SUB(NOW(); INTERVALL 7 DAY)<\/code> not being equal to <code>new \\DateTime('-7 days')<\/code> &#8211; that&#8217;s not what this is about \ud83d\ude09<\/p>\n\n\n<div class=\"ko-fi-button\" data-text=\"Buy me a coffee!\" data-color=\"#0e02f2\" data-code=\"mher30\" id=\"kofiShortcode783Html\" style=\"float: none; text-align: left;\" data-title=\"\"><\/div>\n\n\n\n<div style=\"height:15px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>In SQL Subqueries are pretty common: you need only those records where a certain condition is dependend on the existance or non-existance of records in an associated table.I.e. you want to delete all shoppingbaskets in the database, which are older than, let&#8217;s say 7 days but only if they do not have any items in &#8230; <a title=\"Howto: Symfony doctrine subquery exists\" class=\"read-more\" href=\"https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/\" aria-label=\"Read more about Howto: Symfony doctrine subquery exists\">Read more<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":1093,"footnotes":""},"categories":[49],"tags":[],"class_list":["post-617","post","type-post","status-publish","format-standard","hentry","category-symfony-en"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Howto: Symfony doctrine subquery exists - mher consulting<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Howto: Symfony doctrine subquery exists - mher consulting\" \/>\n<meta property=\"og:description\" content=\"In SQL Subqueries are pretty common: you need only those records where a certain condition is dependend on the existance or non-existance of records in an associated table.I.e. you want to delete all shoppingbaskets in the database, which are older than, let&#8217;s say 7 days but only if they do not have any items in ... Read more\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/\" \/>\n<meta property=\"og:site_name\" content=\"mher consulting\" \/>\n<meta property=\"article:published_time\" content=\"2020-06-21T15:41:11+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-08-15T14:45:13+00:00\" \/>\n<meta name=\"author\" content=\"Michael H.E. Roth\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Michael H.E. Roth\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.mher.de\\\/en\\\/howto-symfony-doctrine-subquery-exists\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.mher.de\\\/en\\\/howto-symfony-doctrine-subquery-exists\\\/\"},\"author\":{\"name\":\"Michael H.E. Roth\",\"@id\":\"https:\\\/\\\/www.mher.de\\\/#\\\/schema\\\/person\\\/239ec7070cb781d59940d3f895b285f7\"},\"headline\":\"Howto: Symfony doctrine subquery exists\",\"datePublished\":\"2020-06-21T15:41:11+00:00\",\"dateModified\":\"2024-08-15T14:45:13+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.mher.de\\\/en\\\/howto-symfony-doctrine-subquery-exists\\\/\"},\"wordCount\":387,\"commentCount\":2,\"articleSection\":[\"Symfony\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.mher.de\\\/en\\\/howto-symfony-doctrine-subquery-exists\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.mher.de\\\/en\\\/howto-symfony-doctrine-subquery-exists\\\/\",\"url\":\"https:\\\/\\\/www.mher.de\\\/en\\\/howto-symfony-doctrine-subquery-exists\\\/\",\"name\":\"Howto: Symfony doctrine subquery exists - mher consulting\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.mher.de\\\/#website\"},\"datePublished\":\"2020-06-21T15:41:11+00:00\",\"dateModified\":\"2024-08-15T14:45:13+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.mher.de\\\/#\\\/schema\\\/person\\\/239ec7070cb781d59940d3f895b285f7\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.mher.de\\\/en\\\/howto-symfony-doctrine-subquery-exists\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.mher.de\\\/en\\\/howto-symfony-doctrine-subquery-exists\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.mher.de\\\/en\\\/howto-symfony-doctrine-subquery-exists\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Startseite\",\"item\":\"https:\\\/\\\/www.mher.de\\\/en\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Howto: Symfony doctrine subquery exists\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.mher.de\\\/#website\",\"url\":\"https:\\\/\\\/www.mher.de\\\/\",\"name\":\"mher consulting\",\"description\":\"Website-Consulting, Wordpress-Hosting, SEO Searchengineoptimization, Online Marketing\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.mher.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.mher.de\\\/#\\\/schema\\\/person\\\/239ec7070cb781d59940d3f895b285f7\",\"name\":\"Michael H.E. Roth\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/7fcf8a987882ef6069cc992d8b43429ac9af464049330f3d130f659b7b0e1110?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/7fcf8a987882ef6069cc992d8b43429ac9af464049330f3d130f659b7b0e1110?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/7fcf8a987882ef6069cc992d8b43429ac9af464049330f3d130f659b7b0e1110?s=96&d=mm&r=g\",\"caption\":\"Michael H.E. Roth\"},\"url\":\"https:\\\/\\\/www.mher.de\\\/en\\\/author\\\/mher\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Howto: Symfony doctrine subquery exists - mher consulting","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/","og_locale":"en_US","og_type":"article","og_title":"Howto: Symfony doctrine subquery exists - mher consulting","og_description":"In SQL Subqueries are pretty common: you need only those records where a certain condition is dependend on the existance or non-existance of records in an associated table.I.e. you want to delete all shoppingbaskets in the database, which are older than, let&#8217;s say 7 days but only if they do not have any items in ... Read more","og_url":"https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/","og_site_name":"mher consulting","article_published_time":"2020-06-21T15:41:11+00:00","article_modified_time":"2024-08-15T14:45:13+00:00","author":"Michael H.E. Roth","twitter_misc":{"Written by":"Michael H.E. Roth","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/#article","isPartOf":{"@id":"https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/"},"author":{"name":"Michael H.E. Roth","@id":"https:\/\/www.mher.de\/#\/schema\/person\/239ec7070cb781d59940d3f895b285f7"},"headline":"Howto: Symfony doctrine subquery exists","datePublished":"2020-06-21T15:41:11+00:00","dateModified":"2024-08-15T14:45:13+00:00","mainEntityOfPage":{"@id":"https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/"},"wordCount":387,"commentCount":2,"articleSection":["Symfony"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/","url":"https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/","name":"Howto: Symfony doctrine subquery exists - mher consulting","isPartOf":{"@id":"https:\/\/www.mher.de\/#website"},"datePublished":"2020-06-21T15:41:11+00:00","dateModified":"2024-08-15T14:45:13+00:00","author":{"@id":"https:\/\/www.mher.de\/#\/schema\/person\/239ec7070cb781d59940d3f895b285f7"},"breadcrumb":{"@id":"https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.mher.de\/en\/howto-symfony-doctrine-subquery-exists\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Startseite","item":"https:\/\/www.mher.de\/en\/"},{"@type":"ListItem","position":2,"name":"Howto: Symfony doctrine subquery exists"}]},{"@type":"WebSite","@id":"https:\/\/www.mher.de\/#website","url":"https:\/\/www.mher.de\/","name":"mher consulting","description":"Website-Consulting, Wordpress-Hosting, SEO Searchengineoptimization, Online Marketing","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.mher.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.mher.de\/#\/schema\/person\/239ec7070cb781d59940d3f895b285f7","name":"Michael H.E. Roth","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/7fcf8a987882ef6069cc992d8b43429ac9af464049330f3d130f659b7b0e1110?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/7fcf8a987882ef6069cc992d8b43429ac9af464049330f3d130f659b7b0e1110?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/7fcf8a987882ef6069cc992d8b43429ac9af464049330f3d130f659b7b0e1110?s=96&d=mm&r=g","caption":"Michael H.E. Roth"},"url":"https:\/\/www.mher.de\/en\/author\/mher\/"}]}},"_links":{"self":[{"href":"https:\/\/www.mher.de\/en\/wp-json\/wp\/v2\/posts\/617","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mher.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mher.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mher.de\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mher.de\/en\/wp-json\/wp\/v2\/comments?post=617"}],"version-history":[{"count":11,"href":"https:\/\/www.mher.de\/en\/wp-json\/wp\/v2\/posts\/617\/revisions"}],"predecessor-version":[{"id":847,"href":"https:\/\/www.mher.de\/en\/wp-json\/wp\/v2\/posts\/617\/revisions\/847"}],"wp:attachment":[{"href":"https:\/\/www.mher.de\/en\/wp-json\/wp\/v2\/media?parent=617"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mher.de\/en\/wp-json\/wp\/v2\/categories?post=617"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mher.de\/en\/wp-json\/wp\/v2\/tags?post=617"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}