#php #mysql
#php #mysql
Вопрос:
У меня возникли некоторые проблемы с извлечением данных из двух таблиц и последующим их перечислением. Я хотел бы перечислить публикации пользователя в ленте и их активность с лайками в одном.
- Каналы — таблица для сообщений пользователей
- Лайки — таблица для лайков пользователей (поэтому, когда пользователю нравится публикация, в likes добавляется запись (таблица
likes
содержитdata
, которая содержитfeeds ID
понравившуюся публикацию)
Что я пытаюсь сделать: перечислите ОБА канала и аналогичную активность пользователя на СТЕНЕ АКТИВНОСТИ.
Таким образом, он должен выводиться следующим образом (упорядоченный по временной метке desc):
- «ЭТО СООБЩЕНИЕ пользователя A»
- Показывает, что пользователю C понравился пост пользователя B
- «ЭТО СООБЩЕНИЕ пользователя B»
- «ЭТО СООБЩЕНИЕ пользователя L»
- Показывает этому пользователю понравившуюся публикацию пользователя F.
- «ЭТО СООБЩЕНИЕ пользователя F»
- -и это продолжается-
Мой текущий SQL:
SELECT * FROM feeds,likes WHERE feeds.deleted!=0 or likes.deleted!=0 ORDER BY feeds.timestamp, likes.timestamp
Однако моя проблема в том, что я понятия не имею, как связать обе таблицы, поскольку идентификаторы в моих «лентах» отличаются от идентификаторов в «лайках»
Комментарии:
1. Есть ли у вас
post_id
илиfeed_id
в таблице лайков? было бы полезно, если бы вы разместили столбцы в обеих таблицах.2. Таблица
likes
содержитdata
, которая содержитfeed post ID
понравившуюся запись3. Вы должны предоставить схемы таблиц, чтобы им было легче 😉
4. Упс, надо было это сделать! Я буду иметь это в виду в следующий раз! Спасибо @Darren 😉
Ответ №1:
Чтобы объединить два набора, вы можете использовать UNION ALL
оператор set.
Что-то вроде этого:
SELECT f.timestamp AS `timestamp`
, 'feed' AS `src`
, f.feed_id AS `id`
, f.feed_content AS `content`
FROM feeds f
WHERE f.deleted!=0
UNION ALL
SELECT l.timestamp AS `timestamp`
, 'like' AS `src`
, l.like_id AS `id`
, l.note AS `content`
FROM likes l
WHERE l.deleted!=0
ORDER BY 1 DESC
Обратите внимание, что запросы (по обе стороны от UNION ALL
оператора) должны совпадать с точки зрения количества возвращаемых столбцов и типа данных каждого столбца.
Чтобы учесть различия, такие как дополнительные столбцы, возвращаемые из одной таблицы, но не из другой, вы можете добавить буквальные выражения вместо «отсутствующих» столбцов.
Возврат дополнительного src
столбца — это один из способов, который мы можем использовать, чтобы отличить, каким запросом была возвращена строка. Возвращать такой столбец не обязательно, но это то, что я часто нахожу полезным. ( src
Столбец может быть удален из каждого запроса, если это не полезно для вашего варианта использования.)
Обратите внимание, что таким образом также возможно объединить результаты более чем из двух запросов, мы бы просто добавили еще один UNION ALL
и еще один запрос.
Имена столбцов в объединенном результирующем наборе определяются из первого запроса. Имена столбцов и псевдонимы во втором запросе игнорируются.
ORDER BY
Применяется ко всему набору и следует за последним выбором.
Комментарии:
1. Это отвечает на вопрос «как мне объединить строки, возвращенные из двух таблиц, в один набор». Для больших наборов операция сортировки влияет на производительность (для удовлетворения
ORDER BY
). Альтернативный дизайн имел бы единую таблицу с временными метками каналов и лайков; и это позволило бы выполнять ORDER BY с использованием индекса, а не операции «Using filesort». Операция «Using filesort». Но на самом деле это ответ на вопрос, который не был задан. Другой альтернативой было бы запустить два запроса отдельно, упорядочить результаты каждого по временной метке и попросить клиента выполнить процесс слияния2. Спасибо за ваш очень информативный ответ! Теперь все работает хорошо! Последний вопрос, как бы мне выполнить объединение для трех таблиц?
3. Чтобы объединить результаты третьего SELECT, просто добавьте непосредственно перед
ORDER BY
другимUNION ALL
оператором set, за которым следует другойSELECT
оператор. Количество возвращаемых столбцов / выражений и тип данных каждого возвращаемого столбца / выражения должны соответствовать предыдущему ВЫБОРУ.
Ответ №2:
Запрос должен быть связан через postID F = таблица каналов, L = таблица лайков, U1 = таблица пользователей, связанная с принадлежащими каналами, U2 = таблица пользователей, связанная с таблицей лайков
SELECT F.postTitle ' posted by ' U1.username,'liked by' U2.username
FROM likes L
LEFT JOIN feeds F on (F.postID=L.postID)
LEFT JOIN users U1 on (U1.userID=F.userID)
LEFT JOIN users U2 on (U2.userID=L.userID)
ORDER BY L.date,L.postID DESC
Комментарии:
1. Я не думаю, что этот запрос возвращает набор результатов, указанный OP. Это не вернет отдельные строки для сообщений и лайков. Кроме того,
оператором является оператор сложения MySQL, и выражения будут оцениваться в числовом контексте. Для конкатенации строк мы обычно используем
CONCAT
функцию.
Ответ №3:
Когда вы пишете SELECT * FROM feeds,likes...
, вы неявно перекрестно соединяете обе таблицы. Движок объединит каждую запись в каждой таблице с каждой записью в другой. Это далеко от того, что вы хотите.
Я также не думаю, что вам следует «связывать» обе таблицы. Грубо говоря, вам нужно получить каждый пост и каждый лайк, а затем упорядочить этот большой набор в соответствии с временными метками.
Это больше похоже на ОБЪЕДИНЕНИЕ между двумя запросами, и ПОРЯДОК ПО применяется ко всему ОБЪЕДИНЕНИЮ. Объединения, кстати, никогда не бросаются в глаза…
Проблема с объединениями заключается в том, что оба подзапроса должны возвращать одинаковое количество столбцов. Не зная точно, какие столбцы у вас есть, я покажу вам одно возможное решение:
SELECT activity, timestamp FROM (
( SELECT CONCAT(u.name,' posted ',f.content) as activity, timestamp
FROM user u
JOIN feed f on (f.user_id=u.id)
WHERE f.deleted!=0
) UNION
( SELECT CONCAT(u.name, ' liked a post by ',u2.name) as activity, timestamp
FROM user u
JOIN likes l on (l.user_id=u.id)
JOIN feed f on (l.feed_id=f.id)
JOIN user u2 on (f.user_id=u2.id)
WHERE l.deleted!=0
)
) as whole_result
ORDER by timestamp desc
Вы должны, конечно, изменить это, чтобы соответствовать вашей структуре.
Надеюсь, это поможет!
Комментарии:
1. Встроенные представления не являются строго необходимыми.
UNION ALL
Оператор set позволил бы избежать накладных расходов наUNION
операцию, которая идентифицирует и удаляет повторяющиеся строки.
Ответ №4:
Я думаю, лучше использовать 3-ю таблицу, скажем, «действия», и вставить в нее реальные действия. Затем просто выберите строки из этой таблицы, объединенные в таблицу «сообщения» и «пользователи».
Когда пользователь публикует статьи, или ему нравится статья, вставьте соответствующую строку в таблицу «действия».
таблица действий:
|id|action_name|user_id|post_id| date |
1 posted 3 3 5/7/2014
2 liked 5 3 5/7/2014
3 liked 4 3 6/7/2014
4 posted 5 6 7/7/2014
5 liked 3 6 7/7/2014
SELECT user_name a, post_title b, action_name c FROM actions c LEFT JOIN users a ON a.id=c.user_id LEFT JOIN posts b ON b.id = c.post_id ORDER BY c.date DESC LIMIT 10
Затем в цикле выберите способ отображения этих данных в соответствии с «action_name».
Таким образом, вы можете расширить свою стену для других действий использовать индексы для повышения производительности базы данных.