Select with third table by id - php

Mysql Detail:
Table A (name: post): id
Table B (name: post_has_relate) : post_id, object_id
Could I get the post in table A with same object_id that post_id is const? I try to write with a sub-query. Could I can write it with a join?
SELECT
p.sumary AS sumary,
p.source_link AS source_link,
p.source_name AS source_name,
p.created AS created,
p.id AS id,
p.slug AS slug
FROM
post_has_relate AS pr
LEFT JOIN post as p ON p.id = pr.post_id
WHERE
pr.object_id IN (
SELECT
post_has_relate.object_id AS object_id
FROM
post_has_relate
WHERE
post_has_relate.post_id = 1052
)
AND pr.post_id != 1052
AND p. STATUS = 1
GROUP BY
p.id
ORDER BY
p.created DESC
LIMIT 5 OFFSET 0

I think you could achieve the same result with a join:
SELECT
p.sumary AS sumary,
p.source_link AS source_link,
p.source_name AS source_name,
p.created AS created,
p.id AS id,
p.slug AS slug
FROM
post_has_relate AS pr
LEFT JOIN post as p ON p.id = pr.post_id
JOIN post_has_relate AS pr2
ON pr2.object_id=pr.object_id AND pr2.post_id=1052
WHERE
pr.post_id != 1052
AND p.STATUS = 1
GROUP BY
p.id
ORDER BY
p.created DESC
LIMIT 5 OFFSET 0

Related

query with dependent subqueries too slow

select mt.from_user, mt.to_user, mt.group_id, g.name, g.created_by as adminuser,
msg.*,
(
SELECT id
from messages
where t.thread_id = thread_id
and id NOT IN (
SELECT message_id from message_deleted
where user_id=275 and status='deleted' )
order by CreatedDate DESC
limit 1
) as msgid,
(
SELECT CreatedDate
from messages
where t.thread_id = thread_id
and id NOT IN (
SELECT message_id from message_deleted
where user_id=275 and status='deleted' )
order by CreatedDate DESC
limit 1
) as msgDate
from user_thread as t
left join message_thread as mt ON t.thread_id = mt.id
left join group_master as g ON mt.group_id = g.id
left join group_member as gm ON gm.group_id = g.id
left join messages as msg ON t.thread_id = msg.thread_id
where ( gm.user_id=275
or msg.from_id=275
or msg.to_id=275
)
and t.status = 'Active'
group by mt.id
order by msgDate DESC
This takes about 50 sec.
In above code, I have try to split above query and note that below subquery take too much time to execute. Can I convert subquery into join. please help me. I am stuck.please note that all tables which are joined are necessary.
(
SELECT id
from messages
where t.thread_id = thread_id
and id NOT IN (
SELECT message_id from message_deleted
where user_id=275 and status='deleted' )
order by CreatedDate DESC
limit 1
) as msgid,
(
SELECT CreatedDate
from messages
where t.thread_id = thread_id
and id NOT IN (
SELECT message_id from message_deleted
where user_id=275 and status='deleted' )
order by CreatedDate DESC
limit 1
) as msgDate
First, You are misusing a notorious MySQL extension to GROUP BY. This will probably cause your results to be unpredictable. Read this. https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
Second, You have a couple of nested dependent subqueries. The first of them is this.
(select id
from messages
where t.thread_id = thread_id
and id NOT IN (select message_id
from message_deleted
where user_id=275
and status='deleted')
order by CreatedDate DESC limit 1) as msgid
Such nested dependent subqueries perform notoriously badly. They're even worse when they contain LIMIT clauses. Your route to fixing this is refactoring into an independent query and then JOINing it.
This may work as a replacement for the query to find the most recent undeleted message on the thread.
SELECT MAX(m.id) id, m.thread_id
FROM messages m
LEFT JOIN message_deleted d
ON m.id = d.id
AND d.user_id = 275
AND d.status = 'deleted'
WHERE d.id IS NULL
GROUP BY m.thread_id
This uses the LEFT JOIN .... IS NULL pattern in place of NOT IN. It's faster. It uses the MAX(id) method of finding the most recent row in a table in place of the ORDER BY CreatedDate DESC LIMIT 1 method, which is also much faster. It's good because it's guaranteed to generate either 0 or 1 row per value of thread_id. That means you can use it in a LEFT JOIN ... ON ... thread_id operation and not add any rows to your result set.
You can test this subquery by running it. Then you JOIN it, as if it were a table, to the rest of your query, something like this.
SELECT whatever,
q.id, r.CreatedDate
FROM whatever
LEFT JOIN (
SELECT MAX(m.id) id, m.thread_id
FROM messages m
LEFT JOIN message_deleted d
ON m.id = d.id
AND d.user_id = 275
AND d.status = 'deleted'
WHERE d.id IS NULL
GROUP BY m.thread_id
) q ON q.id = t.id
LEFT JOIN messages r ON r.id = q.id
The second LEFT JOIN operation here is used to retrieve the CreatedDate value of the newest undeleted message from the messages table.

How to JOIN these 3 tables

I have the following JOIN query already done:
$stmt = $cxn->prepare('SELECT p.post_id, p.reply_to, p.parent_id, p.post_path, p.user_id, p.content, p.datetime, p.total_likes, p.total_replies, p.total_reposts, u.username, u.display_name FROM posts p LEFT JOIN users u ON p.user_id = u.user_id WHERE p.user_id IN (SELECT following_id FROM follows WHERE user_id = ?) AND p.removed != 1 ORDER BY p.datetime DESC LIMIT 26');
$stmt->bind_param('i', $user_info[0]);
$stmt->execute();
I have another query that's only purpose is to check if a row exists or not:
$stmt = $cxn->prepare('SELECT COUNT(like_id) FROM likes WHERE post_id = ? AND user_id = ?');
$stmt->bind_param('ii', $row['post_id'], $user_info[0]); // $row['post_id'] is the value of p.post_id from the first query
$stmt->execute();
How would I join the second query into the first one? I've never joined 3 tables so I'm unsure of the procedure.
Thanks.
Joining three tables in a query is like joining two, except... you join three.
Basically it would go something like this:
SELECT p.post_id (...), u.username (...), COUNT(l.like_id) AS nbOfLikes
FROM posts p
LEFT JOIN users u ON p.user_id = u.user_id
LEFT JOIN likes l ON l.post_id = p.post_id AND l.user_id = u.user_id
WHERE p.user_id IN
(SELECT following_id
FROM follows
WHERE user_id = ?)
AND p.removed != 1
ORDER BY p.datetime DESC
LIMIT 26;
-- Actually I think a UNION would perhaps be more adapted to your need concerning the likes table.
If you always have the user_id filled into your table posts and it's a foreign key, avoid to use a left join statement, you can get a better performance using join statement. To join 3 or more tables you can just add the join statement:
SELECT
p.post_id
, p.reply_to
, p.parent_id
, p.post_path
, p.user_id
, p.content
, p.datetime
, p.total_likes
, p.total_replies
, p.total_reposts
, u.username
, u.display_name
FROM posts p
JOIN users u ON p.user_id = u.user_id WHERE p.user_id IN (SELECT following_id FROM follows
JOIN TABLE_2 ON TABLE_2.id = posts.TABLE_id
JOIN TABLE_3 ON TABLE_3.id = posts.TABLE_id
...
WHERE
user_id = ?)
AND p.removed != 1
ORDER BY p.datetime DESC
LIMIT 26

SUM of a secondSELECT statement - PHP - MySQL

I have the following query which works... but I need some changes:
SELECT
p.pid,
p.name,
GROUP_CONCAT( gC.leaguepoints ORDER BY leaguepoints DESC ) AS leaguepoints
FROM
golf_player p
LEFT JOIN
golf_card gC ON
p.pid = gC.pid
GROUP BY
p.pid
ORDER BY
p.name
DESC
What I really want is another property returned called totalleaguepoints which is a SUM of the most recent 20 league points in my table.
How do I add a limit to a group_concat?
It might be something like this?
SELECT
p.pid,
p.name,
GROUP_CONCAT( gC.leaguepoints ORDER BY leaguepoints DESC ) AS leaguepoints,
SUM(
SELECT
gC2.leaguepoints
FROM
golf_card gC2
WHERE
gC2.pid = p.pid
ORDER BY
leaguepoints
DESC
LIMIT 20
) AS totalleaguepoints
FROM
golf_player p
LEFT JOIN
golf_card gC ON
p.pid = gC.pid
GROUP BY
p.pid
ORDER BY
p.name
DESC
P.S, the above query does not run
Do you want just the top 20 league points for each player in the group_concat as well as the sum?
If so maybe use user variables:-
SELECT
p.pid,
p.name,
GROUP_CONCAT( gC.leaguepoints ORDER BY leaguepoints DESC ) AS leaguepoints,
SUM(gC.leaguepoints) AS totalleaguepoints
FROM golf_player p
LEFT JOIN
(
SELECT pid, leaguepoints, #Sequence:=IF(#PrevPid = pid, #Sequence + 1, 0) AS aSequence, #PrevPid := pid
FROM
(
SELECT pid, leaguepoints
FROM golf_card
ORDER BY pid, leaguepoints DESC
) Sub1
CROSS JOIN (SELECT #PrevPid := 0, #Sequence := 0) Sub2
) gC
ON p.pid = gC.pid AND aSequence < 20
GROUP BY p.pid
ORDER BY p.name DESC

SQL multiple joins SELECT query with MAX()

The following query select the subforums from the database and the last posts in each one of them.
SELECT
forums.*,
MAX(posts.id),
posts.title AS lastmsgtitle,
posts.timee AS lastmsgtime,
posts.useraid AS lastmsguseraid,
posts.useradn AS lastmsguseradn,
users.photo AS lastmsgphoto
FROM forums
LEFT JOIN posts
ON(posts.forumid = forums.id)
LEFT JOIN users
ON(posts.useraid = users.id)
WHERE forums.relatedto='$forumid'
and posts.type='post'
GROUP BY forums.id
ORDER BY `id` DESC
The only problem, the query not select the last post, any ideas why?
FORUMS 1
POSTS 2
I would suggest using a subquery to select the max(id) for each post.
SELECT
f.*, -- replace the f.* with the columns that you need to return
p1.MaxId,
p2.title AS lastmsgtitle,
p2.timee AS lastmsgtime,
p2.useraid AS lastmsguseraid,
p2.useradn AS lastmsguseradn,
u.photo AS lastmsgphoto
FROM forums f
LEFT JOIN
(
select MAX(id) MaxId, forumid
from posts
group by forumid
) p1
ON p1.forumid = f.id
LEFT JOIN posts p2
ON p2.forumid = f.id
and p1.MaxId = p2.id
and p2.type='post'
LEFT JOIN users u
ON p2.useraid = u.id
WHERE f.relatedto='$forumid'
ORDER BY `id` DESC

select n posts per category in a single query

In my home page I show different posts from different categories.
My current implementation is to call query_posts many times (once per category)
How can I use one query to pull out the data?
My tries
1 - this method works(ignore the ugly very long sql,I have many categories...)
Thanks the post: http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
( SELECT *
FROM `wp_posts` p,`wp_term_relationships` rel
WHERE rel.object_id = p.ID
AND rel.term_taxonomy_id = '3'
ORDER BY p.post_date DESC
LIMIT 2)
UNION ALL
( SELECT *
FROM `wp_posts` p,`wp_term_relationships` rel
WHERE rel.object_id = p.ID
AND rel.term_taxonomy_id = '4'
ORDER BY p.post_date DESC
LIMIT 2)
SELECT i.*
FROM wp_term_relationships rel
INNER JOIN (
SELECT p.*, rel2.*
FROM wp_posts p
INNER JOIN wp_term_relationships rel2
ON (rel2.object_id = p.ID)
WHERE rel2.term_taxonomy_id = rel.term_taxonomy_id
ORDER BY p.post_date DESC
LIMIT 2 OFFSET 0 ) i ON (i.object_id = rel.object_id)
WHERE rel.term_taxonomy_id IN ('3','4')
ORDER BY i.term_taxonomy_id ASC, i.post_date DESC

Categories