SQL (MySQL): изменить запрос LEFT JOIN на FULL OUTER JOIN (при нулевых значениях) - как это изменить (без ужасной производительности впоследствии)? - PullRequest
1 голос
/ 06 июля 2019

Имея таблицу настроек Entity-Attribute Value, которая структурирована следующим образом (это из стороннего плагина, я не могу изменить дизайн базы данных):

Table

Теперь я хочу создать таблицу, в которой data_id будет идентификатором, а имена будут столбцами, а значения - их значениями. Тем не менее, каждый data_id не имеет значения для каждого имени, поэтому я хочу, чтобы значение в результате было NULL (или пустым), если в исходной таблице нет значения для этого имени.

Теперь я написал PHP-скрипт, который генерирует для меня требуемый запрос:

$ihash = function($len = 10){
        return substr(str_shuffle(str_repeat("abcdefghijklmnopqrstuvwxyz", 10)), 0, 10);
    };
$columns = $wpdb->get_col("SELECT DISTINCT name FROM ".$wpdb->prefix."cf7_vdata_entry");

$fromselects = [];
$left_joins = [];
$wheres = [];
$used=[];

foreach($columns as $column) {
    $m = $ihash();
    while(in_array($m,$used)) {
        $m = $ihash();
    }
    array_push($used,$m);
    array_push($fromselects,"$m.value as `$column`");
    $left_joins  .= " LEFT JOIN wp_cf7_vdata_entry AS $m ON a.data_id = $m.data_id ";
    array_push($wheres,"$m.name = '$column'");
}

$query = "SELECT a.data_id, ".implode(", ",$fromselects)."
  FROM (SELECT DISTINCT data_id FROM wp_cf7_vdata_entry) AS a JOIN
  ".$left_joins."
 WHERE ".implode(" AND ",$wheres);

Вот так выглядит сгенерированный запрос:

SELECT a.data_id, 
       vtddnqrdjy.value AS `foerderung`, 
       fwfyxgczvn.value AS `company`, 
       jwlpmnbepe.value AS `firstname`,
       -- ... more fields
FROM   (SELECT DISTINCT data_id 
        FROM   wp_cf7_vdata_entry) AS a 
       JOIN wp_cf7_vdata_entry AS vtddnqrdjy 
         ON a.data_id = vtddnqrdjy.data_id 
       JOIN wp_cf7_vdata_entry AS fwfyxgczvn 
         ON a.data_id = fwfyxgczvn.data_id 
       JOIN wp_cf7_vdata_entry AS jwlpmnbepe 
         ON a.data_id = jwlpmnbepe.data_id 
       -- ... more joins
WHERE  vtddnqrdjy.name = 'foerderung' 
       AND fwfyxgczvn.name = 'company' 
       AND jwlpmnbepe.name = 'firstname' 
       AND mloxjygcqp.name = 'lastname' 
       -- ... more fields
LIMIT  10 

Таблица результатов сгенерирована правильно, но результат пуст:

result table

Причина в том, что результаты, которые не имеют значений ВСЕХ столбцов, отфильтровываются, но вместо этого они должны иметь нулевые значения (имеющие ровно один результат для каждого data_id, существующего в таблице). Я думал о замене всех LEFT JOIN с FULL OUTER JOIN с (что должно быть подделано в MySQL), но это усложняет ситуацию и, вероятно, и без того плохая производительность будет крайне плохой. Как я мог решить это?

1 Ответ

1 голос
/ 06 июля 2019

MySQL не поддерживает FULL OUTER JOIN.Вместо этого используйте агрегацию:

SELECT de.data_id,
       MAX(CASE WHEN de.name = 'foerderung' THEN de.value END) as foerderung, 
       MAX(CASE WHEN de.name = 'company' THEN de.value END) as company
           . . .   -- just repeat for each column
FROM wp_cf7_vdata_entry de
GROUP BY de.data_id;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...