Let’s learn recursive CTE SQL via paragraphs

We are going through a partial relaunch and it came up twice to find the nodes which have a certain paragraph somewhere. The first one was just a request to return a list of nodes, the second however required writing an update function to do something with the node. I implemented the first using MySQL 8.0 (MariaDB 10.2 works too) installed locally but the second one required Drupal code written for a lower database version. This provides us with the opportunity to share code with you that does the same in PHP and then in a recursive CTE. Without further ado:

<?php
$db = Drupal::database();
$ids = $db->query('SELECT entity_id FROM {paragraph__field_lc_video_ref}')->fetchCol();
$all_ids = $ids;
do {
  $parents = $db->query('SELECT parent_id FROM {paragraphs_item_field_data} WHERE id IN (:ids[]) AND parent_type = :paragraph', [':ids[]' => $ids, ':paragraph' => 'paragraph'])->fetchCol();
  $all_ids = array_merge($all_ids, $parents);
  $ids = $parents;
} while ($parents);
$nids = $db->query('
  SELECT DISTINCT parent_id 
  FROM {paragraphs_item_field_data} 
  INNER JOIN {node_field_data} n ON parent_id = nid AND n.status = 1 
  WHERE id IN (:ids[]) AND parent_type = :node', [':ids[]' => $all_ids, ':node' => 'node'])->fetchCol();

And then the CTE:

CREATE TEMPORARY TABLE x 
SELECT entity_id FROM paragraph__field_article_section_body 
UNION
SELECT entity_id FROM paragraph__field_article_section_title;
WITH RECURSIVE r AS (
  SELECT id, parent_id, parent_type
  FROM paragraphs_item_field_data
  WHERE id IN (SELECT entity_id FROM x)
  UNION ALL
  SELECT r.id, parent.parent_id, parent.parent_type
  FROM r
  INNER JOIN paragraphs_item_field_data parent ON parent.id = r.parent_id
  WHERE r.parent_type = 'paragraph'
)
SELECT DISTINCT nid
FROM r
INNER JOIN node_field_data n on nid = r.parent_id

May 15, 2020


Next post
Understanding Drupal cache contexts via history and code The Drupal cache system is just a key-value store. Say, your key is “left sidebar”, the value is the HTML of the left sidebar. Very simple. But if