Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: Выборка из 2-х таблиц даже при том, что для полей одной таблицы может не существовать полей другой
Форумы портала PHP.SU » » Работа с СУБД » Выборка из 2-х таблиц даже при том, что для полей одной таблицы может не существовать полей другой

Страниц (1): [1]
 

1. SkaN - 29 Августа, 2014 - 07:17:46 - перейти к сообщению
В заголовке очень сумбурно описал, потому что я не очень понимаю, как это описать лучше. Вот расширенное:
Есть две таблицы: одна с постами, а в другой есть все данные для постов (это Wordpress и его таблицы _posts и _postmeta). Во всех данных структура такая: entry_id, post_id, meta_key, meta_value. Для некоторых записей из таблицы _posts есть запись в таблице _postmeta, которая соответствует условию
CODE (SQL):
скопировать код в буфер обмена
  1. WHERE `_posts`.`post_id` = `_postmeta`.`post_id` AND `_postmeta`.`meta_key` = '_yourls'

Но в то же время для некоторых такой записи просто не существует, даже со значением NULL. То есть по запросу получается вытащить либо те посты, для которых есть _yourls, либо те, для которых нет. Я решил это UNION'ом, получилось так:
CODE (SQL):
скопировать код в буфер обмена
  1. SET @start='2014-08-27 21:32:00';
  2. SELECT * FROM (
  3.     SELECT `site_posts`.`ID` AS `id`, `site_posts`.`post_author` AS `author`, `site_posts`.`post_title` AS `title`, `site_posts`.`post_date_gmt` AS `date`, `site_postmeta`.`meta_value` AS `url`
  4.     FROM `site_posts`
  5.     LEFT OUTER JOIN `site_postmeta` ON `site_postmeta`.`post_id` = `site_posts`.`ID`
  6.     WHERE `post_date_gmt` > @start
  7.     AND `site_postmeta`.`meta_key` = '_yourls_url'
  8.     AND `post_type` = 'post'
  9.     AND `post_status` = 'publish'
  10.     AND `site_posts`.`post_author` NOT IN (202, 224, 226, 201, 200, 225)
  11.  
  12. UNION DISTINCT
  13.  
  14.     SELECT `site_posts`.`ID` AS `id`, `site_posts`.`post_author` AS `author`, `site_posts`.`post_title` AS `title`, `site_posts`.`post_date_gmt` AS `date`, NULL AS `url`
  15.     FROM `site_posts`
  16.     WHERE `post_date_gmt` > @start
  17.     AND `post_type` = 'post'
  18.     AND `post_status` = 'publish'
  19.     AND `site_posts`.`post_author` NOT IN (202, 224, 226, 201, 200, 225)
  20.     AND NOT EXISTS (
  21.         SELECT * FROM `site_postmeta` WHERE `site_postmeta`.`post_id` = `site_posts`.`ID` AND `site_postmeta`.`meta_key` = '_yourls_url'
  22.     )
  23. ) AS `new_posts`
  24. GROUP BY `author`, `title`
  25. ORDER BY `date` DESC;

Но тут наступает некоторая задница, потому что пусть запрос отрабатывает красиво, возвращая один набор данных, но сам запрос не до конца оптимизирован и почти что не расширяем. Теперь вопросы:
Как мне можно сначала выбрать посты по одинаковым условиям из обоих запросов? Подозреваю, что тут мне помогут вложенные SELECT'ы.
Другой вопрос: как мне можно в один набор данных объединить посты, для которых есть _yourls и посты, для которых нет, так, чтобы, если _youls есть, то он выбирался, а если нет, чтобы на его месте был NULL?
Спасибо за старания понять мою писанину Радость
2. Мелкий - 29 Августа, 2014 - 07:22:59 - перейти к сообщению
left join
3. SkaN - 30 Августа, 2014 - 00:26:49 - перейти к сообщению
CODE (SQL):
скопировать код в буфер обмена
  1. SET @start='2014-08-27 21:32:00';
  2. SELECT `site_posts`.`ID` AS `id`, `site_posts`.`post_author` AS `author`, `site_posts`.`post_title` AS `title`, `site_posts`.`post_date_gmt` AS `date`, `site_postmeta`.`meta_value` AS `url`
  3. FROM `site_posts`
  4. LEFT JOIN `site_postmeta` ON `site_postmeta`.`post_id` = `site_posts`.`ID`
  5. WHERE `post_date_gmt` > @start
  6. AND `site_postmeta`.`meta_key` = '_yourls_url'
  7. AND `post_type` = 'post'
  8. AND `post_status` = 'publish'
  9. AND `site_posts`.`post_author` NOT IN (202, 224, 226, 201, 200, 225)

Сделал так, выбираются только те посты, для которых есть поле _yourls, те, для которых нет, не выбираются вообще.
4. SkaN - 30 Августа, 2014 - 03:34:12 - перейти к сообщению
CODE (SQL):
скопировать код в буфер обмена
  1. SELECT `site_posts`.`ID` AS `id`, `site_posts`.`post_author` AS `author`, `site_posts`.`post_title` AS `title`, `site_posts`.`post_date_gmt` AS `date`, `yourls`.`url` AS `url`
  2. FROM `site_posts`
  3. LEFT JOIN (
  4.     SELECT `post_id`, `meta_value` AS `url`
  5.     FROM `site_postmeta`
  6.     WHERE `meta_key` = '_yourls_url'
  7. ) AS `yourls` ON `yourls`.`post_id` = `id`
  8. WHERE `post_date_gmt` > '2014-08-25 21:32:00'
  9. AND `post_type` = 'post'
  10. AND `post_status` = 'publish'

Вот такое решение. Сделал встроенный запрос, чтобы изолировать условие WHERE `meta_key` = '_yourls_url'. Если его добавить в основной запрос, то возвращается только то, что имеет такое поле.
5. Мелкий - 30 Августа, 2014 - 10:52:48 - перейти к сообщению
CODE (SQL):
скопировать код в буфер обмена
  1. SELECT `site_posts`.`ID` AS `id`, `site_posts`.`post_author` AS `author`, `site_posts`.`post_title` AS `title`, `site_posts`.`post_date_gmt` AS `date`, `site_postmeta`.`meta_value` AS `url`
  2. FROM `site_posts`
  3. LEFT JOIN `site_postmeta` ON `site_postmeta`.`post_id` = `site_posts`.`ID` AND `site_postmeta`.`meta_key` = '_yourls_url'
  4. WHERE `post_date_gmt` > @start
  5. AND `post_type` = 'post'
  6. AND `post_status` = 'publish'
  7. AND `site_posts`.`post_author` NOT IN (202, 224, 226, 201, 200, 225)

 

Powered by ExBB FM 1.0 RC1