Using INNER JOIN to receive crossed data by date range - mysql

I have a theme gallery. In the dashboard i have to display the most viewed themes BY date (today, last 7 days, last 30 days, all time).
These are the 2 involved tables:
theme
id_theme
title
views
id_view
id_theme
date
The $timestamp values are calculated with mktime() (no prob in there).
This is my current SQL query:
SELECT t.id_theme,t.title,
(SELECT COUNT(*)
FROM views
WHERE views.id_theme=t.id_theme
AND views.date BETWEEN '.$timestamp1.' AND '.$timestamp2.')
AS q
FROM theme AS t
INNER JOIN views ON t.id_theme = views.id_theme
GROUP BY views.id_theme
ORDER BY q
DESC LIMIT 10
The problem is that The catch, is that sometimes it receives themes with 0 views, and that should not happen. I tried changing the INNER JOIN with RIGHT JOIN with no results. Any ideas?

Hmm. not sure why you're using subqueries for this, seems like this would work better:
SELECT theme.id_theme, theme.title, COUNT(views.id_view) as view_count
FROM theme
LEFT JOIN views ON (theme.id_theme = views.id_theme)
GROUP BY theme.id_theme
WHERE views.date > DATE_SUB(now() INTERVAL 30 day)
ORDER BY view_count DESC
HAVING view_count > 0

SELECT t.id_theme, t.title, COUNT(*) AS q
FROM theme AS t
INNER JOIN views ON t.id_theme = views.id_theme
AND views.date BETWEEN '.$timestamp1.' AND '.$timestamp2.'
GROUP BY t.id_theme, t.title
ORDER BY q
DESC LIMIT 10

Related

Searching and Sorting Using MySQL Inner Join

I guess I can't explain my problem properly. I want to explain this to you with a picture.
Picture 1
In the first picture you can see the hashtags in the trend section. These hashtags are searched for the highest total and it is checked whether the date has passed. If valid data is available, the first 5 hashtags are taken.
Picture 2
In the second picture, it is checked whether the posts in the hashtag are in the post, if any, the oldest date value is taken, LIMIT is set to 1 and the id value from the oyuncular table is matched with sid. Thus, the name of the person sharing can be accessed.
Picture 3
My English is a little bad, I hope I could explain it properly.
SELECT
social_trend.hashtag,
social_trend.total,
social_trend.tarih,
social_post.sid,
social_post.tarih,
social_post.post,
oyuncular.id,
oyuncular.isim
FROM
social_trend
INNER JOIN
social_post
ON
social_post.post LIKE '%social_trend.hashtag%' ORDER BY social_post.tarih LIMIT 1
INNER JOIN
oyuncular
ON
oyuncular.id = social_post.sid
WHERE
social_trend.tarih > UNIX_TIMESTAMP() ORDER BY social_trend.total DESC LIMIT 5
YOu should use a sibquery
and add a proper join between subqiery and social_trend
(i assumed sing both sid)
SELECT
social_trend.hashtag,
social_trend.total,
social_trend.tarih,
t.sid,
t.tarih,
t.post,
oyuncular.id,
oyuncular.isim
FROM (
select social_post.*
from social_post
INNER JOIN social_trend ON social_post.post LIKE concat('%',social_trend.hashtag,'%' )
ORDER BY social_post.tarih LIMIT 1
) t
INNER JOIN social_trend ON social_trend.hashtag= t.post
INNER JOIN oyuncular ON oyuncular.id = t.sid
WHERE
social_trend.tarih > UNIX_TIMESTAMP() ORDER BY social_trend.total DESC LIMIT 5
but looking to your new explanation and img seems you need
SELECT
t.hashtag,
t.total,
t.tarih_trend,
t.sid,
t.tarih,
t.post,
oyuncular.id,
oyuncular.isim
FROM (
select social_post.sid
, social_post.tarih
, social_post.post
, st.hashtag
, st.total
, st.tarih tarih_trend
from social_post
INNER JOIN (
select * from social_trend
WHERE social_trend.tarih > UNIX_TIMESTAMP()
order by total DESC LIMIT 5
) st ON social_post.post LIKE concat('%',st.hashtag,'%' )
ORDER BY social_post.tarih LIMIT 5
) t
INNER JOIN oyuncular ON oyuncular.id = t.sid

How can I build inner query to find trend top 3

Question about SQL. The schema is given below:
User(userID:int, userName:varchar(30), email:varchar(30), password:varchar(30), status:varchar(15))
Video(videoID:int, userID:int, videoTitle:varchar(60), likeCount:int, dislikeCount:int, datePublished:date)
Comment(commentID:int, userID:int, videoID:int, commentText:varchar(1000), dateCommented:date)
Watch(userID:int, videoID:int, dateWatched: date)
Same variables will be using as foreign key. Because of this I do not need to write foreign keys.
A)
List the trending top three videos for a given time interval
(String dateStart, String dateEnd)
A trending video is defined to be the most viewed video in the given interval (i.e., video that is viewed the highest numberof times among all).
You should include dateStart and dateEnd in the result, it is a CLOSED interval.
Output: videoTitle, userName, number of times that the video watched.
I could not figured out how can i find top tree videos. While building inner query what should I do?
If you want the top 3 videos for a period of time, you can do:
select v.videotitle, u.username, count(*) no_watches
from watch w
inner join video v on v.videoid = w.videoid
inner join usr u on u.userid = v.userid
where w.date_watched between ? and ?
group by v.videoid, u.userid
order by no_watches desc
limit 3
The between predicate is how I understand the "closed interval". The ? relate to query parameters that contain the start and end date.
Pre-aggregation might make the query more efficient:
select v.videotitle, u.username, w.no_watches
from (
select videoid, count(*) as no_watches
from watch
where date_watched between ? and ?
group by videoid
order by no_watches desc limit 3
) w
inner join video v on v.videoid = w.videoid
inner join usr u on u.userid = v.userid
order by w.no_watches desc
limit 3

MYSQL Union from left and right and group

I have a forum with two tables forum_posts and forum_replies. I need to get the most active users. Here is what I recently tried
SELECT forum_reply.added_by, forum_posts.added_by FROM forum_reply LEFT JOIN forum_posts ON forum_posts.added_by = forum_reply.added_by
UNION
SELECT forum_posts.added_by, forum_reply.added_by FROM forum_posts RIGHT JOIN forum_reply ON forum_reply.added_by = forum_posts.added_by
WHERE forum_reply.date_added < '".$now."' AND forum_reply.date_added > '".$past24h."' AND forum_posts.date_added < '".$now."' AND forum_posts.date_added > '".$past24h."'
GROUP BY forum_reply.added_by, forum_posts.added_by ORDER BY COUNT(*) DESC LIMIT 5");
The problem is this query gives me only one result instead of 5. And the result is definitely not real because the user this query gives me haven't posted anything for the last 24 hours.

Count tweets between dates (mysql)

I have an assignment to create a twitter like database. And in this assignment i have to filter out the trending topics. My idea was to count the tweets with a specific tag between the date the tweet was made and 7 days later, and order them by the count.
I have the following 2 tables i am using for this query :
Table Tweet : id , message, users_id, date
Table Tweet_tags : id, tag, tweet_id
Since mysql isn't my strong point at all im having trouble getting any results from the query.
The query i tried is :
Select
Count(twitter.tweet_tags.id) As NumberofTweets,
twitter.tweet_tags.tag
From twitter.tweet
Inner Join twitter.tweet_tags On twitter.tweet_tags.tweet_id = twitter.tweet.id
WHERE twitter.tweet_tags.tag between twitter.tweet.date and ADDDATE(twitter.tweet.date, INTERVAL 7 day)
ORDER BY NumberofTweets
The query works, but gives no results. I just can't get it to work. Could you guys please help me out on this, or if you have a better way to get the trending topics please let me know!
Thanks alot!
This is equivalent to your query, with table aliases to make it easier to read, with BETWEEN replaced by two inequality predicates, and the ADDDATE function replaced with equivalent operation...
SELECT COUNT(s.id) As NumberofTweets
, s.tag
FROM twitter.tweet t
JOIN twitter.tweet_tags s
ON s.tweet_id = t.id
WHERE s.tag >= t.date
AND s.tag <= t.date + INTERVAL 7 DAY
ORDER
BY NumberofTweets
Two things pop out at me here...
First, there is no GROUP BY. To get a count by "tag", you want at GROUP BY tag.
Second, you are comparing "tag" to "date". I don't know your tables, but that just doesn't look right. (I expect "date" is a DATETIME or TIMESTAMP, and "tag" is a character string (maybe what my daughter calls a "hash tag". Or is that tumblr she's talking about?)
If I understand your requirement:
For each tweet, and for each tag associated with that tweet, you want to get a count of the number of other tweets, that have a matching tag, that are made within 7 days after the datetime of the tweet.
One way to get this result would be to use a correlated subquery. (This is probably the easiest approach to understand, but is probably not the best approach from a performance standpoint).
SELECT t.id
, s.tag
, ( SELECT COUNT(1)
FROM twitter.tweet_tags r
JOIN twitter.tweet q
ON q.id = r.tweet_id
WHERE r.tag = s.tag
AND q.date >= t.date
AND q.date <= t.date + INTERVAL 7 DAY
) AS cnt
FROM twitter.tweet t
JOIN twitter.tweet_tags s
ON s.tweet_id = t.id
ORDER
BY cnt DESC
Another approach would be to use a join operation:
SELECT t.id
, s.tag
, COUNT(q.id) AS cnt
FROM twitter.tweet t
JOIN twitter.tweet_tags s
ON s.tweet_id = t.id
LEFT
JOIN twitter.tweet_tags r
ON r.tag = s.tag
LEFT
JOIN twitter.tweet q
ON q.id = r.tweet_id
AND q.date >= t.date
AND q.date <= t.date + INTERVAL 7 DAY
GROUP
BY t.id
, s.tag
ORDER
BY cnt DESC
The counts from both of these queries assume that tweet_tags (tweet_id, tag) is unique. If there are any "duplicates", then including the DISTINCT keyword, i.e. COUNT(DISTINCT q.id) (in place of COUNT(1) and COUNT(q.id) respectively) would get you the count of "related" tweets.
NOTE: the counts returned will include the original tweet itself.
NOTE: removing the LEFT keywords from the query above should return an equivalent result, since the tweet/tag (from t/s) is guaranteed to match itself (from r/q), as long as the tag is not null and the tweet date is not null.
Those queries are going to have problematic performance on large sets. Appropriate covering indexes are going to be needed for acceptable performance:
... ON twitter.tweet_tags (tag, tweet_id)
... ON twitter.tweet (date)

MySQL Subquery returned more than 1 row

I cannot figure out why this is not working. Basically, I am running a subquery to count all rows of p.songid WHERE trackDeleted=0. The subquery works fine when I execute it by itself, but when I implement I get "subquery returned more than 1 row".
SELECT u.username, u.id, u.score, s.genre, s.songid, s.songTitle, s.timeSubmitted, s.userid, s.insWanted, s.bounty,
(SELECT COUNT(p.songid)
FROM songs s
LEFT JOIN users u
ON u.id = s.userid
LEFT JOIN posttracks p
ON s.songid = p.songid
WHERE p.trackDeleted=0
GROUP BY s.timeSubmitted ASC
LIMIT 25)
AS trackCount
FROM songs s
LEFT JOIN users u
ON u.id = s.userid
LEFT JOIN posttracks p
ON s.songid = p.songid
WHERE paid=1 AND s.timeSubmitted >= ( CURDATE() - INTERVAL 60 DAY )
GROUP BY s.timeSubmitted ASC
LIMIT 25
Obviously, a sub-query can't return more than one row, as this makes no sense. You only expect one value to be returned - COUNT(p.songid) - yet you GROUP BY s.timeSubmitted, which will make it return multiple rows, and multiple counts of p.songid.
Think about it this way, a subquery in the SELECT statement like you have needs to return a single value since it is going to act like just another column in your select list. Since you have a LIMIT 25 on yours, you're obviously expecting more than one value back, which is inocrrect for this usage.
OK, your query is a mess. Not only is the subquery broken, but I'm pretty sure the GROUP BY s.timeSubmitted ASC isn't doing what you think think it does. (Did you mean ORDER BY instead?) It might help if you explained in words what you're trying to accomplish.
Anyway, I'm going to take a wild guess and suggest that this might be what you want:
SELECT
u.username, u.id, u.score, s.genre, s.songid, s.songTitle,
s.timeSubmitted, s.userid, s.insWanted, s.bounty,
COUNT(p.songid) AS trackCount
FROM songs s
LEFT JOIN users u ON u.id = s.userid
LEFT JOIN posttracks p ON p.songid = s.songid AND p.trackDeleted = 0
WHERE paid = 1 AND s.timeSubmitted >= ( CURDATE() - INTERVAL 60 DAY )
GROUP BY s.songid
ORDER BY s.timeSubmitted ASC
LIMIT 25
Edit: Fixed the COUNT() so that it will correctly return 0 if there are no matching tracks.