Как эмулировать полное внешнее соединение в этом запросе?

Итак, видимо, mySQL не поддерживает полное внешнее соединение, но это действительно то, что мне нужно. Я видел кучу сообщений в блогах и статей о том, как подражать этому с помощью союзов, но это удаляет дубликаты. Может кто-нибудь помочь мне здесь?

Вот запрос, содержащий полное внешнее соединение (здесь выполняется только одно соединение из нескольких); как бы я перевел это во что-то, что понимает mySQL?

SELECT DISTINCT n.title, nr.teaser, n.nid, DATE_FORMAT(FROM_UNIXTIME(n.created), '%M %e, %Y') AS date, f.filepath AS image,tn_img.tid as image_tid

FROM node n 

JOIN node_revisions nr ON n.nid = nr.nid 
LEFT JOIN content_field_related_images cfri ON (n.nid = cfri.nid AND cfri.delta = 0) 
LEFT JOIN content_field_att_file cfaf ON cfri.field_related_images_nid = cfaf.nid 
LEFT JOIN files f ON cfaf.field_att_file_fid = f.fid   
JOIN term_node tn2 ON n.nid = tn2.nid 
FULL OUTER JOIN term_node tn_img ON cfri.field_related_images_nid = tn_img.nid

WHERE n.status = 1 
AND n.type = 'article'   
AND nr.body LIKE '%kimberly-clark%' 
AND tn2.tid = 143

ORDER BY n.created DESC LIMIT 3

person EmmyS    schedule 24.05.2011    source источник
comment
Возможно, вы захотите взглянуть на stackoverflow.com/questions/ 4796872/full-outer-join-in-mysql или stackoverflow.com/questions/2384298/   -  person Conrad Frix    schedule 24.05.2011
comment
Я уже прочитал их (и все связанные статьи/сообщения), но не смог экстраполировать то, что они предлагали, на мой запрос. Это действительно расширяет пределы моих знаний sql.   -  person EmmyS    schedule 24.05.2011
comment
Это классно. Возможно, вы захотите добавить ссылки на вопросы, которые вы просматривали, чтобы вопрос не был закрыт как дубликат ... и, конечно же, язвительные комментарии.   -  person Conrad Frix    schedule 24.05.2011
comment
@EmmyS: Конрад Фрикс... хороший ответ......!   -  person Himanshu Agnihotri    schedule 16.10.2012


Ответы (1)


Вы в основном делаете союз LEFT и RIGHT JOIN.

На самом деле у вас есть интересная проблема в том, что вы также хотите ограничить количество строк до 3. Чтобы решить эту проблему, вам нужно

  • Ограничьте выбор «левого» и «правого» на 3
  • Затем используйте результат UNION во встроенном представлении.
  • затем снова ограничьте союз на 3

ОБНОВЛЕНИЕ К сожалению, если я не ошибаюсь, вы не можете сделать это непосредственно в UNION, поэтому вам нужно добавить еще один уровень встроенных представлений перед UNION.

LIMITS внутри UNION будет предлагать некоторое преимущество в производительности, а затем ограничение после даст вам правильные результаты.

SELECT title, 
   teaser, 
   nid, 
   DATE, 
   image, 
   image_tid 
FROM   (SELECT title, 
               teaser, 
               nid, 
               DATE, 
               image, 
               image_tid,
               created 
        FROM   (SELECT DISTINCT n.title, 
                                nr.teaser, 
                                n.nid, 
                                Date_format(From_unixtime(n.created), 
                                '%M %e, %Y') AS 
                                DATE, 
                                f.filepath 
                                AS 
                                image, 
                                tn_img.tid 
                                AS 
                                image_tid 
                                       , 
                                n.created 
                FROM   node n 
                       JOIN node_revisions nr 
                         ON n.nid = nr.nid 
                       LEFT JOIN content_field_related_images cfri 
                         ON ( n.nid = cfri.nid 
                              AND cfri.delta = 0 ) 
                       LEFT JOIN content_field_att_file cfaf 
                         ON cfri.field_related_images_nid = cfaf.nid 
                       LEFT JOIN files f 
                         ON cfaf.field_att_file_fid = f.fid 
                       JOIN term_node tn2 
                         ON n.nid = tn2.nid 
                       LEFT OUTER JOIN term_node tn_img 
                         ON cfri.field_related_images_nid = tn_img.nid 
                WHERE  n.status = 1 
                       AND n.TYPE = 'article' 
                       AND nr.body LIKE '%kimberly-clark%' 
                       AND tn2.tid = 143 
                ORDER  BY n.created DESC 
                LIMIT  3) tleft 
        UNION 
        SELECT title, 
               teaser, 
               nid, 
               DATE, 
               image, 
               image_tid,
               created  
        FROM   (SELECT DISTINCT n.title, 
                                nr.teaser, 
                                n.nid, 
                                Date_format(From_unixtime(n.created), 
                                '%M %e, %Y') AS 
                                DATE, 
                                f.filepath 
                                AS 
                                image, 
                                tn_img.tid 
                                AS 
                                image_tid 
                                       , 
                                n.created 
                FROM   node n 
                       JOIN node_revisions nr 
                         ON n.nid = nr.nid 
                       LEFT JOIN content_field_related_images cfri 
                         ON ( n.nid = cfri.nid 
                              AND cfri.delta = 0 ) 
                       LEFT JOIN content_field_att_file cfaf 
                         ON cfri.field_related_images_nid = cfaf.nid 
                       LEFT JOIN files f 
                         ON cfaf.field_att_file_fid = f.fid 
                       JOIN term_node tn2 
                         ON n.nid = tn2.nid 
                       RIGHT OUTER JOIN term_node tn_img 
                         ON cfri.field_related_images_nid = tn_img.nid 
                WHERE  n.status = 1 
                       AND n.TYPE = 'article' 
                       AND nr.body LIKE '%kimberly-clark%' 
                       AND tn2.tid = 143 
                ORDER  BY n.created DESC 
                LIMIT  3) tright) t 
ORDER  BY created DESC 
LIMIT  3 

ОБНОВЛЕНИЕ Используя предложения spencer7593 и ypercube, здесь предлагается альтернативный подход с использованием двух операторов UNION ALL и без встроенных представлений.

SELECT DISTINCT n.created, 
                n.title, 
                nr.teaser, 
                n.nid, 
                Date_format(From_unixtime(n.created), '%M %e, %Y') AS DATE, 
                f.filepath                                         AS image, 
                tn_img.tid                                         AS image_tid 
FROM   node n 
       JOIN node_revisions nr 
         ON n.nid = nr.nid 
       LEFT JOIN content_field_related_images cfri 
         ON ( n.nid = cfri.nid 
              AND cfri.delta = 0 ) 
       LEFT JOIN content_field_att_file cfaf 
         ON cfri.field_related_images_nid = cfaf.nid 
       LEFT JOIN files f 
         ON cfaf.field_att_file_fid = f.fid 
       JOIN term_node tn2 
         ON n.nid = tn2.nid 
       LEFT OUTER JOIN term_node tn_img 
         ON cfri.field_related_images_nid = tn_img.nid 
WHERE  n.status = 1 
       AND n.TYPE = 'article' 
       AND nr.body LIKE '%kimberly-clark%' 
       AND tn2.tid = 143 

UNION ALL 
SELECT DISTINCT n.created, 
                n.title, 
                nr.teaser, 
                n.nid, 
                Date_format(From_unixtime(n.created), '%M %e, %Y') AS DATE, 
                f.filepath                                         AS image, 
                tn_img.tid                                         AS image_tid 
FROM   node n 
       JOIN node_revisions nr 
         ON n.nid = nr.nid 
       LEFT JOIN content_field_related_images cfri 
         ON ( n.nid = cfri.nid 
              AND cfri.delta = 0 ) 
       LEFT JOIN content_field_att_file cfaf 
         ON cfri.field_related_images_nid = cfaf.nid 
       LEFT JOIN files f 
         ON cfaf.field_att_file_fid = f.fid 
       JOIN term_node tn2 
         ON n.nid = tn2.nid 
       RIGHT JOIN term_node tn_img 
         ON cfri.field_related_images_nid = tn_img.nid 
WHERE  n.status = 1 
       AND n.TYPE = 'article' 
       AND nr.body LIKE '%kimberly-clark%' 
       AND tn2.tid = 143 
       AND cfri.field_related_images_nid IS NULL 
ORDER  BY 1 DESC 
LIMIT 
3 
person Conrad Frix    schedule 24.05.2011
comment
Вау, это страшно выглядит! Я попробую и посмотрю, что он вернет. Спасибо. - person EmmyS; 24.05.2011
comment
ОК, только что попробовал и получил следующее: #1054 - Неизвестный столбец «создан» в «пункте заказа». Я попытался изменить окончательное предложение order by на n.created, но это дало мне ту же ошибку, поэтому я не уверен, о чем идет речь. Кроме того, не могли бы вы объяснить, что означает cfri.delta = 0? - person EmmyS; 24.05.2011
comment
@Emmy - в запросе UNION или UNION ALL предложение ORDER BY ссылается на столбцы по положению, а не по имени (например, чтобы получить набор результатов, упорядоченный по первому столбцу в наборе результатов, ORDER BY 1). Также рассмотрите возможность использования UNION ALL вместо UNION, чтобы избежать удаления повторяющихся строк. - person spencer7593; 24.05.2011
comment
@ЭммиС. Извините за то, что я забыл включить созданный в tright и tleft, я обновил ответ. - person Conrad Frix; 25.05.2011
comment
@ spencer7593 - проблема с порядком в том, что мы пытаемся упорядочить записи по столбцу, который на самом деле не включен во внешний запрос для отображения (создания) - так как мы с этим справимся? - person EmmyS; 25.05.2011
comment
@ spencer7593 при эмуляции FULL OUTER JOIN вы действительно хотите UNION, а не UNION ALL - person Conrad Frix; 25.05.2011
comment
@Conrad - на самом деле можно использовать UNION ALL в запросе, который эмулирует FULL OUTER JOIN (что вы хотели бы сделать, чтобы сохранить дубликаты), используя три запроса: внутреннее соединение, левое соединение и правое соединение. например SELECT . FROM l INNER JOIN r UNION ALL SELECT . FROM l LEFT JOIN r WHERE r.id IS NULL UNION ALL SELECT . FROM l RIGHT JOIN r WHERE l.id IS NULL - person spencer7593; 25.05.2011
comment
@ spencer7593 Добавлен альтернативный вариант с использованием ваших предложений. - person Conrad Frix; 25.05.2011
comment
Извините за взлом, не прочитав весь запрос, но нельзя ли FULL OUTER JOIN выполнить UNION ALL из 2 запросов: (SELECT . FROM l LEFT JOIN r) UNION ALL (SELECT . FROM l RIGHT JOIN r WHERE l.id IS NULL) ? - person ypercubeᵀᴹ; 25.05.2011
comment
@Emmy - к сожалению, единственный известный мне способ ‹b›гарантировать‹/b›, что набор результатов из запроса UNION возвращается в определенном порядке, - это ORDER BY столбцов, на которые ссылается позиция. (По крайней мере, таков был мой опыт. Если я не включу ORDER BY в самый внешний запрос, то (согласно спецификации SQL) механизм базы данных может возвращать кортежи (строки) в любом порядке, в котором он хочет. . - person spencer7593; 25.05.2011
comment
@ypercube - да, плохо, внутреннее соединение и одно из внешних соединений могут быть свернуты, так что это будет два запроса, как вы и предлагаете.) - person spencer7593; 25.05.2011