I have a series of news articles, that are stored inside a database, like so:
id
articleTitle
articleBody
articleBy
category
dateEntered
What I want to do is select all of the articles and group them by a particular month / year that they were entered. For example:
May
News article 1
News article 2
News article 3
Feb
News article 4
News article 5
News article 6
I am able to select the months, as well as how many items are there, using the following:
SELECT id, articleTitle, YEAR(dateEntered) AS 'year', MONTH(dateEntered) AS 'month' FROM News GROUP BY YEAR(dateEntered), MONTH(dateEntered) DESC
Whenever I try to output the contents of 'articleTitle' it only shows 1 result, when there should be 28 entries that are showing.
Where am I going wrong in my query?
The GROUP BY clause collapses sets of rows with common values for the expressions in the GROUP BY clause. With this in your query:
GROUP BY YEAR(dateEntered), MONTH(dateEntered)
The query will only return a single row for distinct values of those expressions. There is nothing wrong with doing this. This is convenient if you want to return a count of the number of rows that have that year and month, for example
SELECT DATE_FORMAT(dateEntered,'%Y-%m')
, COUNT(1) AS cnt_
FROM mytable
GROUP BY DATE_FORMAT(dateEntered,'%Y-%m')
If you don't want your query to "collapse" the rows, then don't use a GROUP BY clause.
I suspect you want to use an ORDER BY clause, not a GROUP BY. To make the order the rows are returned in more deterministic, you can add more expressions to the ORDER BY clause. Also note that ASC and DESC apply to each expression in the ORDER BY clause.
For example:
SELECT n.id
, n.articleTitle
, YEAR(n.dateEntered) AS `year`
, MONTH(n.dateEntered) AS 'month'
FROM News n
ORDER
BY YEAR(n.dateEntered) DESC
, MONTH(n.dateEntered) DESC
, n.id DESC
Related
First I am new to SQL and PHP.
I have created a simple social networking web app so users can post and follow others to see new posts from them.
At home page a user can first see posts from all users he is followong.
but what i want is to make the user see some other random popular posts that will be ordered by Likes.
here what i have done to get posts from users i follow:
SELECT * FROM posts WHERE author_id in
(SELECT followedID FROM follows WHERE
followerID=:myID)
ORDER BY id DESC LIMIT 10
Now let's say you are following only 1 person. and that person has only one post. here you will see no more than a post!
That's why i want to show more posts when a user has already seen all posts.
i want some easy way to get other posts when the above query has done getting some specific posts.
This is the next query i'd like to execute.
SELECT * FROM posts ORDER BY post_likes DESC LIMIT 10
I wouldn't recommend union, because it incurs overhead for removing duplicates.
Instead, you can use a LEFT JOIN:
SELECT p.*
FROM posts p LEFT JOIN
follows f
ON p.author_id = f.follows_id AND
f.followerID = :myID
ORDER BY (f.follows_id IS NOT NULL) DESC,
(CASE WHEN f.follows_id IS NOT NULL THEN p.id END),
p.post_likes DESC
LIMIT 10;
The ORDER BY puts the followed posts first. The other two clauses order each of the groups by the criteria you want.
You may use UNION to do what you want
(SELECT * FROM posts WHERE author_id in
(SELECT followedID FROM follows WHERE
followerID=:myID)
ORDER BY id DESC limit 0,10)
union
(SELECT * FROM posts ORDER BY post_likes DESC limit 0,10)
LIMIT 0, 10
UNION will automatically append the 2nd query result to the 1st query result, and then show only the number of records specified by the LIMIT clause
Please note that union works only if the queries are of the same structure (which in this case is positive)
Please note that the use of parenthesis is mandatory if you use order by or limit or both
I have used 3 limit clauses (one for each query , and one for the final result of union) AND Both queries have ORDER BY clause. This is to make sure that the records extracted are what you want. (to show the followed posts first, and both are ordered properly)
I have been struggling with this problem for about month..
Have been searching and reading many posts, but still can't figure out, how to make this work..
Basically: I got 2 database tables fun_posts and fun_post_upvotes And I want to
SELECT *
FROM fun_posts
ORDER BY (HOTTEST POSTS(MOST UPVOTED THIS WEEK))
This is my latest code, that won't work
SELECT *
FROM fun_posts
ORDER BY (SELECT count(*), image_id, date
FROM fun_post_upvotes
GROUP BY image_id
ORDER BY DATE(date) > (NOW() - INTERVAL 7 DAY) DESC,
count(*) DESC,
date DESC)
If I divide this line into 2 different SELECT functions, they work. I can select simple posts and I can select upvotes count ordered like I want.
But If I make them into one line like that, I get following error:
#1241 - Operand should contain 1 column(s)
EDIT NR 1:
fun_posts table
fun_post_upvotes table
Problem with Answer that I checked:
Here, look how posts are ordered in my select function. (It selects like I want) 10->134->132->2->13
And here with given code (It selects image, but not in that order) 10->122->39->8->110
You can use a join to do this
SELECT fp.*, fpu.`cnt`
FROM fun_posts fp
LEFT JOIN ( SELECT image_id, COUNT(*) AS cnt
FROM fun_post_upvotes
WHERE `date` > (NOW() - INTERVAL 7 day)
GROUP BY image_id
) fpu ON ( fpu.image_id = fp.id )
ORDER BY fpu.cnt DESC, fp.`date` DESC, fp.`id` DESC;
It selects a list from fun_post_upvotes grouped by image_id and counts the amount of rows. That list is returned to the main query and matches (LEFT JOIN) on fp.id. The query will first show the item with the most upvotes in the past 7 days, than the least. If no upvotes are found, the result will still return them, but at the bottom in no specific order.
You can edit the order by, to obtain the items in the order you like.
Here a sqlfiddle.com
I'm trying to figure out how to do this on my own but it looks like a dead end to me.
I am working under wordpress framework and with some custom tables.
The result i am trying to achieve is very simple but the way to get there is just too much for my head right now.
I need to select the top 50 results from tableOne based on the ammount of times that the id from tableOne is mentioned in tableTwo under some simple where conditions.
Using $wpdb class for the latest WordPress build, what can i use to achieve this?
Thanks
This is the Simple tableOne Query to get all posts:
$allPosts = $wpdb->get_results("SELECT * FROM pokeGrid_images WHERE status='0' ORDER BY tempo DESC LIMIT ".$limit." OFFSET ".$offset."");
Now i need the first 50 results from this table, based on the number of times their id is mentioned on the second table with this structure: http://prntscr.com/byz2qw
Edit:
http://prntscr.com/byz79b
Note: Basically this is a forum, table one has the posts, table 2 the upvotes.
The expression must gather the most upvoted posts for the last X days.
If it was 1 post the expression would be Select Count(*) FROM tableTwo Where tempo > then ".$variableWithUnixTimeDIff."
column tempo is a now() timestamp.
Thanks
Note: Basically this is a forum, table one has the posts, table 2 the
upvotes. The expression must gather the most upvoted posts for the
last X days. If it was 1 post the expression would be Select Count(*)
FROM tableTwo Where tempo > then ".$variableWithUnixTimeDIff."
SELECT *, Sum(score) AS totalScore FROM tableTwo INNER JOIN tableOne ON tableTwo.memeID = tableOne.id GROUP BY memeID ORDER BY totalScore DESC;
Try this query.
//Edit - I just created a sample table with my own data. I only created the tableTwo, where this query did work:
SELECT *, Sum(score) AS totalScore FROM tableTwo GROUP BY memeID ORDER BY totalScore DESC
So after that, just inner join data from tableOne and it will work!
So I am trying to select multiple rows from multiple tables based on date. So there are comments, votes and reviews. Normally I would grab 10 votes based on date, then 10 comments based on date, then 10 reviews. However I want to do this all at once so they are sorted.
How can I say grab 30 (votes + reviews + comments) (all separate tables) so that I get a unique mix of comments / votes/ reviews and always the most recent 30. I assume its something like:
SELECT * from votes, comments, reviews ORDERBY 'created_at', 'DESC'
You can do it with UNION
SELECT created_at, votecomment AS comment FROM votes
UNION ALL
SELECT created_at, comment AS comment FROM comments
UNION ALL
SELECT created_at, reviewcomment AS comment FROM reviews
ORDER BY created_at DESC
LIMIT 30;
What you've got is a cartesian query. If each of those tables has (say) 100 records, then you'll end up with 100x100x100 = 1,000,000 returned records.
Try:
SELECT *
FROM (
SELECT 'votes' AS source_table, * FROM votes ORDER BY created_at DESC LIMIT 10
UNION ALL
SELECT 'comments', * FROM comments ORDER BY created_at DESC LIMIT 10
UNION ALL
SELECT 'reviews', * FROM reviews ORDER BY created_at DESC LIMIT 10
) AS required_alias
ORDER BY created_at DESC
Each of the subqueries fetches the 10 most recent records from your three 3 tables. The outer query takes those 30 rows, and re-sorts them so those 30 rows are again in date/time ordering.
The fixed string votes/comments/reviews stuff is simply so you can identify WHICH table the individual records came from afterwards.
And of course, this will only work if the three tables have identical structures. If they have differing numbers of fields and/or the types differ, the the union will fail.
This is one way to return the specified resultset:
SELECT v.created_at, v.fee AS fee, v.fi AS fi FROM votes v
UNION ALL
SELECT c.created_at, c.fo AS fee, '' AS fi FROM comments c
UNION ALL
SELECT r.created_at, r.fum AS fee, r.foo AS fi FROM reviews r
ORDER BY 1 DESC
LIMIT 30
Note that the number of columns returned by each query must match, and the datatypes returned by each query must match.
(To make the columns "line up", we can include extra expressions in the SELECT list, like shown in the query from the comments table above. An expression can also do datatype conversions as well. The aliases assigned to the columns in the second and third queries don't matter, the names of the columns in the resultset are derived from the first select. They are included in the example above just as a demonstration of getting columns "line up"... the aliases aren't important.)
So i have a whole load of votes going into a voting system. I want to display how many votes i have in any one day. But i also want to then, display the amount of votes per day and spit out which day they were voted on, i.e 24k votes on 05/06/12, 27k votes on 06/06/12
SELECT count(*) AS count
FROM results
GROUP BY DAY(datesubmitted), YEAR(datesubmitted), MONTH(datesubmitted)
ORDER BY DAY(datesubmitted) DESC, YEAR(datesubmitted) DESC, MONTH(datesubmitted) DESC
Is my query, i tried to add something like
DAY(FROM_UNIXTIME(datesubmitted)) as order_day
but this just throws a null which i found interesting as i'd expect the query to fail as there aren't any outers.
Why don't you simply GROUP BY datesubmitted DESC? Also, no need to ORDER BY if it's following the same criteria as GROUP BY.
Number of votes on a specific day:
SELECT COUNT(*) AS total
FROM results
WHERE datesubmitted BETWEEN #dateMin AND #dateMax
Number of votes for each separate day:
SELECT COUNT(*) AS total, DATE(datesubmitted) AS day
FROM results
GROUP BY DATE(datesubmitted)
ORDER BY DATE(datesubmitted) DESC
UPDATED AGAIN
So just saw a new answer but for me how i got it working was:
SELECT count(*) AS count, DAY(datesubmitted) AS newday,
YEAR(datesubmitted) as newyear ,MONTH(datesubmitted) as newmonth
FROM results
GROUP BY DAY(datesubmitted), YEAR(datesubmitted), MONTH(datesubmitted)
ORDER BY YEAR(datesubmitted) DESC, MONTH(datesubmitted) DESC, DAY(datesubmitted) DESC
This way i get the correct ordering with year, month and day properly and also it displays the dates. I could concat them, but thats for another day.