Select max 5 integers from set of 20 - php

I'm trying to select the 5 most viewed articles out of a list of the 20 most recent entries in a table. My table structure is essentially this:
id | date | title | content | views
My first thought was just to use an inner select to get the 20 most recent articles, then select from that, but I have yet to have any luck.
//doesn't work (my version of mysql doesn't support LIMIT in sub queries)
$recent = "(SELECT id FROM news ORDER BY date DESC LIMIT 20)";
$result = $db->query("SELECT id, title, date, content FROM news WHERE id IN $recent ORDER BY views DESC LIMIT ".self::RECENT_MAX);
//neither does this (syntax error # 'OFFSET 20')
$recent = "(SELECT MAX(date) FROM news ORDER BY date DESC OFFSET 20)";
$result = $db->query("SELECT id, title, date, content FROM news WHERE date > $recent ORDER BY views DESC LIMIT ".self::RECENT_MAX);
Anyone got any suggestions on how you would structure this query?

I just tested this and it works
SELECT *
FROM (
SELECT *
FROM news
ORDER BY id DESC
LIMIT 0, 20
) lasttwenty
ORDER BY views DESC
LIMIT 0, 5
Server version: 5.0.51a-3ubuntu5.4

If you're having a lot of issues getting it to work through SQL, I'd suggest just grabbing the 20 most recent articles from the database, then process it in PHP to find the 5 most-viewed. You could either loop over the rows, or just load it all into an array and sort it.

Since I can't think of any way to do that in a single query, I suggest either selecting the top 5 in code, or doing it using two queries, something like:
$items = $db->query("SELECT id FROM news ORDER BY date DESC LIMIT 20");
$recent = array();
foreach ($items->fetchAll() as $item) { $recent[] = $item['id']; }
$recent = "('".join("','", $recent)."')";
$result = $db->query("SELECT id, title, date, content FROM news WHERE id IN {$recent} ORDER BY views DESC LIMIT ".self::RECENT_MAX);

Why don't you run the first (inner) query separately, and create the second query programmatically?
$ids = array();
$result = $db->query("SELECT id FROM news ORDER BY date DESC LIMIT 20");
while ($row = $result->fetch()) {
$ids[] = $row[0];
}
$ids = implode(',', $ids);
$result = $db->query("SELECT id, title, date, content FROM news WHERE id IN ($ids) ORDER BY views DESC LIMIT ".self::RECENT_MAX);
Or something of this nature...
Update: Or you could just simply fetch the first 20 sorted by date, then sort thr result array by views in PHP, and finally take the 5 topmost items (I guess this is what SilentGhost meant in the comment).

Try this...
select top 5 number from
(
select
top 20 (ID) as number
from
news order by date desc
)
as number
EDIT FOR MS SQL
Use the LIMIT for MYSQL

Related

Mysql build query with multiple constraints

I am trying to set up a query that outputs the 5 most read articles over the last 4hrs. However, if there are no new articles over the last 4hrs, the list will be empty. What I would like is a query that outputs 5 articles over the last 4hrs. If there are no 5 articles in the last 4hrs, but lets say only 2, I would like to add 3 more newest articles to the list (sorted by log_time).
So the query should always output 5 articles.
I am wondering if this can be done in one query.
$sqlCommand = "SELECT * FROM feeds where category like '$category' AND log_time > NOW() - INTERVAL 4 HOUR ORDER BY feed_hits DESC LIMIT 5";
$query = mysqli_query($myConnection, $sqlCommand) or die (mysqli_error());
While ($row = mysqli_fetch_array($query)) {
$fid1 = $row["id"];
$feed_id1 = $row["feed_id"];
$link1 = $row["link"];
$title1 = $row["title"];
$output .= '' . $title1 . '<br/>';
}
mysqli_free_result($query);
echo $output;
You can achieve this via a UNION query. The first half of the below query is simply your original query, which may return up to 5 matching records. The second half of the query returns an arbitrary number of records which are older than 4 hours. The entire query is then ordered by log time, with a limit of 5. This puts your recent target records first, with the older records taking any available positions should they be needed.
SELECT *
FROM
(SELECT * FROM feeds
WHERE category like '$category' AND log_time > NOW() - INTERVAL 4 HOUR
ORDER BY feed_hits DESC LIMIT 5) t1
UNION ALL
(SELECT * FROM feeds
WHERE category like '$category' AND log_time <= NOW() - INTERVAL 4 HOUR) t2
ORDER BY log_time DESC
LIMIT 5;
You could not limit for 4 HOUR and order by log_time limit 5
"SELECT *
FROM feeds
where category like '$category'
ORDER BY log_time DESC LIMIT 5";
and if you need ordered by feed_hits you can reorder the result set
"select * from ( SELECT *
FROM feeds
where category like '$category'
ORDER BY log_time DESC LIMIT 5 ) t order by feed_hits ";
Simply remove the time filtering and instead order by time, this will always give you the latest:
SELECT * FROM feeds WHERE category LIKE '$category' ORDER BY log_time DESC, feed_hits DESC LIMIT 5

TOP 10 article visitor counting via PDO PHP

I wanted to know if it is possible to obtain the 10 most viewed articles that week (Between today and 7 days back) using PDO PHP.
The main problem is that on two separate tables. Primary table is the table of articles. And the second table is a table visitors by IP.
Posts (ARTICLE TABLE):
1.ID (text)
2.TITLE (text)
3.TEXT (text)
Visitor (COUNTER TABLE):
1.ID (number)
2.IP (text)
3.DATE (TIMESTAMP)
4.ID_POSTS (text)
The full php code:
$week_start = date('Y-m-d',time()+( 1 - date('w'))*24*3600);
$week_end = date('Y-m-d',time()+( 7 - date('w'))*24*3600);
$query = "SELECT * FROM visitor WHERE DATE BETWEEN '".$week_start."' AND '".$week_end."' LIMIT 0, 10 ";
$result = $db->prepare($query);
$result->execute();
$i=1;
while($row = $result->fetch(PDO::FETCH_ASSOC)) {
$post[$i]=$row[ID];
$i++;
}
for ($i = 1; $i <= 10; $i++) {
$query = "SELECT * FROM POSTS WHERE ID_POST = '".$post[$i]."' LIMIT 0, 10";
$result = $db->prepare($query);
$result->execute();
while($row = $result->fetch(PDO::FETCH_ASSOC)) {
echo<<<PRINT
$row[ID].$row[TITLE]: $row[text]
PRINT;
}
}
The problem I think is that you have to count how many people were at the table wrote the secondary then move the primary table.
Steps:
1. Count how many entered each article each week by the secondary table
2. extract the 10 Most Viewed same week
3. present the 10 most read article in the same week by the main table
Thanks in advance.
For such a query, I would expect a COUNT(), GROUP BY, ORDER BY, and LIMIT 10. Hence:
SELECT id_post, COUNT(*) as cnt
FROM visitor v
WHERE DATE BETWEEN '".$week_start."' AND '".$week_end."'
GROUP BY id_post
ORDER BY cnt DESC
LIMIT 0, 10 ;
Note: The WHERE clause always followed the FROM clause.
Also, you should not be embedding dates in the query string. You should learn to use parameters instead.
select * from (select id, count(1) as cnt
from visitor where date > (NOW()- INTERVAL 7 DAY) group by id) v1, posts p
where v1.id = p.id
order by v1.cnt desc
limit 10
Not tested.

in SQL/PHP returning id with the highest and 2nd-5th highest date

As said in the title, I need FIVE queries that returns the ID for rows with the 1st-5th most recent date.
Table: film
id releasedate
232143 2013-06-20
536523 2013-07-20
453554 2013-08-20
098776 2013-09-20
549302 2013-10-20
i.e the first query would return the id 549302
I think this would work for the first query:
$first = $db->query("SELECT id, FROM film WHERE MAX(releasedate)" );
PS: Sorry for the poor formatting of this post, can anyone tell me how to display tables appropriately?
I need to display each id at different points on the web page. Simply returning a list of ids won't suffice. What I really need is for each id to be encapsulated into a unique variable so i can call them at different points on the web page.
No, you don't need five queries.
$first = $db->query("SELECT `id` FROM `film` ORDER BY `releasedate` DESC LIMIT 5" );
This will get the IDs from the database of the five most recent films in your table.
To access each of these just run through a while loop.
while($row = $first->fetch_assoc()) {
$row['id']; # Each ID will be available like this.
}
If you really need to do this in separate queries, you can use the 2-argument form of the LIMIT clause, which is LIMIT offset, count. To get the newest film, use
SELECT id FROM film ORDER BY releasedate DESC LIMIT 0, 1
To get the 2nd most recent film, use
SELECT id FROM film ORDER BY releasedate DESC LIMIT 1, 1
the next one is
SELECT id FROM film ORDER BY releasedate DESC LIMIT 2, 1
and so on.
But it should be better to get them all in one query with
SELECT id FROM film ORDER BY releasedate DESC LIMIT 5
You can then save them all in an array with:
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$ids[] = $row['id'];
}
Then you can use $ids[0] to display the most recent film, $ids[1] for the second most recent, and so on.

Deleting older database entries

I'm trying to keep the 10 most recent entries in my database and delete the older ones. I tried DELETE FROM people ORDER BY id DESC LIMIT $excess, but it just deleted the top 10 entries.
$query = "SELECT * FROM people";
$result = mysqli_query($conn, $query);
$count = mysqli_num_rows($result);
if ($count > 10) {
$excess = $count - 10;
$query = "DELETE FROM people WHERE id IN(SELECT id FROM people ORDER BY id DESC LIMIT '$excess')";
mysqli_query($conn, $query);
}
You can use this:-
DELETE FROM `people`
WHERE id NOT IN (
SELECT id
FROM (
SELECT id
FROM `people`
ORDER BY id DESC
LIMIT 10
)
);
Also your query is logically incorrect and you are fetching the records in descending order. i.e. Latest to older and you are deleting the most recent records. Use ASC instead.
Something like this? Gets the ten latest ids in the subquery, then deletes all of the other ids.
DELETE FROM people WHERE id NOT IN (SELECT id FROM PEOPLE ORDER BY id DESC LIMIT 10)
Your logic is all over the place, [you should ORDER BY ASC, not DESC] and your query will take ages if there are [for example] 10,000 entries because you'll have an IN clause with 9,990 entries to compare all 10,000 to.
Select the 10 most recent, and delete where NOT in.
DELETE FROM people
WHERE id NOT IN(
SELECT id
FROM people
ORDER BY id DESC
LIMIT 10
)
Maybe find the ID of the 10th element and then delete all rows which are older?

Display 5 most recent forum posts

So I have 3 tables inside of my database, let's say 1_comments, 2_comments and 3_comments and I want to display the latest 5 posts of all 3 tables at once in PHP and sort by the most recent time. My code is:
<?php
$row="";
$link = mysql_connect("localhost","username","password");
mysql_select_db("database");
$query = "SELECT * from 1_comments ORDER by timestamp DESC limit 5";
$result = mysql_query($query);
while($row = mysql_fetch_array($result)) {
echo "<ul>";
echo "<li>".$row['comment']."</li>";
echo "</ul>";
}
mysql_close($link);
?>
So it's taking the most recent 5 posts from the comments row on 1_comments and sorting them by their most recent timestamp, but I can't seem to get it working for 1_comments, 2_comments and 3_comments all at once.
If all tables have the same structure you can use UNION.
Something like:
(SELECT * from 1_comments ORDER by timestamp DESC limit 5)
UNION
(SELECT * from 2_comments ORDER by timestamp DESC limit 5)
UNION
(SELECT * from 3_comments ORDER by timestamp DESC limit 5)
ORDER BY timestamp DESC limit 5
However, I would take a good look at the database structure and try to reduce the 3 similar tables to just one.

Categories