I would like to create 20 rows of table data for to store recently viewed pages. The table row should not increase above 20 rows.
For an example, first 20 rows of page id with title will be stored in that table. when the 21st page viewed by the user, then the first post id and post title will be deleted (i.e., first viewed post) and insert (i.e., last viewed post) in the same table.
my table format:
-------------------------------|
ID | Post Title
-------------------------------|
1 | Post Title 1
2 | Post Title 2
3 | Post Title 3
...
20 | Post Title 20
-------------------------------|
if anyone please tell me how to do that with optimized qry.
You have two columns id and title. Let's consider that id will have any value even more than 20. At any time this table will contain maximums 20 rows (as per your need).
Understand following terms:
min(id) // will give minimum value in column id
max(id) // will give maximum value in column id
count(id) // counts total number of rows of your table
new_id // id of row which will be inserted next
Algorithm:
if(count(id)<20) // table have less than 20 rows so only insert
new_id = max(id)+1
insert the row with id as 'new_id' and page title
else // table have more than 20 rows so delete and then insert
delete row with id = min(id)
new_id = max(id)+1
insert the row with id as 'new_id' and page title
What above solution propose is if you have less than 20 rows keep on inserting because space is still there to insert. But, when you see that rows are more than or equal to 20 first delete the row with minimum id then insert the new row with maximum id of column by adding one.
You can do the following:
LOCK TABLES mytable;
INSERT INTO mytable (title) VALUES ('newtitle');
DELETE t FROM mytable t WHERE t.id IN (SELECT t2.id FROM (SELECT * FROM mytable) t2 ORDER BY t2.id DESC LIMIT 20,999999999); --Delete from 20 to "end"
UNLOCK TABLES;
First you need to add one column in table like created date
while inserting new record to this table, first check total number of rows in table
If rows count == 20 then write a query to delete one old record. use created_date to find it out...
if row count is < 20 then you can insert record directly...no pre-check required
Above step can be managed in only one query, If you are good at writing query
when user has viewed a page:
$query = mysqli_query("SELECT COUNT(ID) From your-table",$conn);
$result = mysqli_fetch_array($query);
$total = $row[0];
if($total<20){
//INSERT NEW ROW
$query = "INSERT INTO your-table() values(...,...)";
//etc ...
} else{
// DELETE THE FIRST ROW
$query = "DELETE FROM your-table ORDER BY ID ASC LIMIT 1";
// Then insert new row, etc...
}
Related
I have created a simple rating system for news articles. The news articles are stored in the database table called 'articles'. Each article has a unique id, starting from 1.
So I have 2 articles, ID 1 and ID 2.
I also have a table called 'ratings' that takes the users unique ID, the article ID and the rating that the user gave.
If I give an article with ID 2 a 5/5 star rating, it goes into the 'ratings' table, with article ID 2, my user ID and the rating of 5.
I have figured out how to display the average rating of each article, but I would like to find out how to show the BEST average rating of articles in descending order. Is that at all possible? How could this be done?
Here is how I find the average:
<?
$votesForThis = 0;
$sql = "SELECT * FROM ratings WHERE articleID = ".$articleID." ORDER BY id ASC";
// Check if there are results
if ($result = mysqli_query($con, $sql)) {
// Loop through each row in the result set
while($row = mysqli_fetch_assoc($result)) {
$votesForThis++;
}
}
$result = mysqli_query($con, 'SELECT SUM(vote) AS vote_sum FROM ratings WHERE articleID=' . $articleID);
$row = mysqli_fetch_assoc($result);
$voteSum = $row['vote_sum'];
$averageVotes = $voteSum / $votesForThis;
?>
MySQL has an avg function you can use instead of implementing this logic yourself. From there, it's just a matter of grouping by the article ID and ordering by the average:
SELECT articleID, AVG(vote)
FROM ratings
GROUP BY articleID
ORDER BY 2 DESC
The best practice for doing this is to add a new column to your article table called average_rating and update it with a cron job or after every voting.
Keep in mind that after a while your rating table will become giant and calculating average rating on every page refresh will put huge load on your server.
I would use de-normalization in this one.
I would use triggers to update a previously created column on table articles which would store it's average rating.
I would have posted an example of trigger but you haven't posted which database are you using.
Mysql: https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html
Postgresql: https://www.postgresql.org/docs/9.1/sql-createtrigger.html
Each time a rating it's done, updated or deleted a trigger would update this column with it's current average using the built-in avg function.
At the end you'll only have to create a select on the articles table ordered by this rating column desc.
And create an index on this average rating column to have even faster results.
SELECT articleID, AVG(vote)
FROM ratings
GROUP BY articleID,vote
ORDER BY DESC
used this Query
I want to count all rows that infront of a specific ID, so I can output how many entries are infront of the users entry.
I have no clue how to count the rows, starting at the ID of the user (for ex. ID 10).
How to count from ID 10 to ID 1 where status = unpublished
Thx
Are you looking for something like-
SELECT COUNT(*)
FROM your_table
WHERE ID BETWEEN 1 AND 10
AND STATUS = 'unpublished'
Try This --
SELECT COUNT(*)
FROM tablename
WHERE ID BETWEEN 1 AND 10
AND STATUS = 'unpublished'
ORDER by ID DESC
SELECT * FROM
WHERE ID = 10 AND status='unpublished';
Hello I need to empty all table except the x new rows i have already test
How to delete all rows from a table except newest 10 rows
SQL Delete all rows except for last 100
But not work, my mysql version doesn't support limit "IN"
(actual version Ver 14.14 Distrib 5.5.46)
My table is like that
ID (int)
DATE (timestamp)
Who i can empty without loop ? Thanks
Try this
<?php
$mysqli=new mysqli("localhost", "root", "", "db");
$result=$mysqli->query("select id from tabl order by id desc" );
$res=$result->fetch_array();
echo $res[0];
$id=$res[0]-100;
$mysqli->query("delete from table where id < $id");
?>
You can do it with a single SQL DELETE statement that uses variables:
DELETE mytable
FROM mytable
INNER JOIN (
SELECT ID, #rn := #rn + 1 AS rn
FROM mytable
CROSS JOIN (SELECT #rn := 0) AS var
ORDER BY DATE DESC
) AS t ON mytable.ID = t.ID
AND t.rn > 100
The derived tasble t is used to assign each ID of mytable a row number. Numbering uses ORDER BY DATE DESC, hence 100 most recent records are going to have rn in [1-100]. DELETE removes any row of mytable except those having rn in [1-100].
Demo here (Demo keeps 10 more recent records instead of 100)
You can do it by using number of SQL statments one after another.
You can do it by get the first ID that you want to delete, and then delete all the rows newer that ID
// Create the memory table for storing the IDs
create table mem(
first100 integer
);
// Insert to the memory table the list of 100 last ids
insert into mem(first100) select id from table order by id desc limit 100;
// Insert to Mysql variable #a, the id of the first id to delete
set #a=select fist100 from mem order by id limit 1;
// Delete all the id's after the one you want to delete
delete from table where id>=#a
Update:
I posted this answer befor you wroted that the error message is: This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME
Anyway, I keep it, maybe this method will help to someone else .
I have a mysql table "orders" contains 3 fields id, user_id and order_id
I want to remove the row having user_id and order_id same, and the row with greater id would not be deleted which is id = 3 in this scenario.
So the result would be looking like this,
First duplicate record should be inserted and then delete the duplicate record.
DELETE n1 FROM orders n1, orders n2 WHERE n1.id < n2.id AND n1.user_id = n2.user_id AND n1.order_id = n2.order_id;
I'm writing a simple URL rotator for a client and they want the URLs to rotate according to the oldest one that was previously displayed.
My columns are very simple:
url_id | company_id | url | last_clicked
I want to fetch a single row where the company_id is passed in and the last_clicked is the minimum of all records matching the company_id.
It should also select a random url_id if all last_clicked values are empty.
I assume this can be accomplished with a GROUP BY and HAVING but I can't seem to get the query to return anything.
I have this:
$last = $this->db->fetchOne ("SELECT url_id FROM
{$this->prefix}urls GROUP BY company_id HAVING MIN(last_clicked)
WHERE company_id='$company'");
This will fetch the row where last_clicked is smallest, or at random if they are all NULL:
SELECT url_id FROM urls
WHERE company_id = $company
ORDER BY last_clicked, RANDOM() LIMIT 1;
An index based on company_id and last_clicked would greatly help:
CREATE INDEX urls_ndx ON urls(company_id, last_clicked);
SELECT url_id FROM
TABLE
WHERE company_id='$company'
AND last_clicked = ( SELECT MIN(last_clicked)
FROM TABLE WHERE company_id='$company' )