I have a table with named "user-recent-activity" which has following columns: id, userid, activity and datetime. Now, I want to delete the records if any unique userid has more than 50 items, deleting the oldest records. For example, if the user id(lets say 1234) has more than 50 records in this table, then I have to save latest 50 records of user id(1234) and delete the oldest one.
Before inserting, query for the last 50 records with that ID (ordering from newer to older). If there is a 50th, substitute it (via update) instead of inserting a new row.
Assuming you are using a RDBMS that supports standard SQL the following stored procedure should do it.
create procedure remove-old-activities
(
#userid int
)
as
delete from user-recent-activity where userid=#userid and id not in (select top 50 id from user-recent-activity where userid=#userid order by datetime desc)
If you're DB does not support stored procedures then you should be able to use SQL parameters to pass the userid value...
Hope that helps
You could use rank method to precisely defined the rows number and thus delete the rows you want.
delete from tblName where id=
(select id from (
select #i := CASE WHEN ( #userid <> userid ) THEN 1
ELSE #i+1
END AS rank , id,userid, datetime2 ,#userid:=userid AS clset
from tblName x,(SELECT #i:=0) a ,(SELECT #userid:= 0) s
order by x.userid, datetime2 desc) T
where T.rank='50') ;
Another option:
Use the select query to select the rank <=50 and insert into a new table. Delete the old table and rename the new table afterwards.
insert into newtable (userid,activity,datetime2)
select userid,datetime2 from (
select #i := CASE WHEN ( #userid <> userid ) THEN 1
ELSE
#i+1
END AS rank , userid, activity,datetime2 ,#userid:=userid AS clset
from tblName x,(SELECT #i:=0) a ,(SELECT #userid:= 0) s
order by x.userid, datetime2 desc) T
where t.rank <=50
Related
I have a query that want to compute each user_id's rank in comparison to all all other user_id real time. Real-time means when query is executing:
My query is as below, but unfortunately computed rank field is not as desired:
SELECT user_id, SUM(COALESCE(`duration`, 0)) AS duration_total,
(SELECT COUNT(*)
FROM `forms`
GROUP BY `user_id`
HAVING SUM(`duration`) > duration_total
) AS rank
FROM `forms`
GROUP BY `user_id`
The problem is on Having condition in the internal select. Where I want to count user_id that have more duration than current user_id.
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 .
Well I have this mysql table with numbers in one column and a confirmation boolean of 0 or 1 and I have about 1,000 rows so it's not something I can do manually but anyways...
I want to sort the row by highest value and grab the names of the first 5 people and put those 5 people in another table on a column and then set them to confirmed and continue until there's no one left in the table that isn't confirmed...
ex:
Name:Rank:Confirm
Bob:5000:0
James:34:0
Josh:59:1
Alex:48:0
Romney:500:0
Rolf:24:0
Hat:51:0
so when you run the code it will do the following:
Squad:Name1:Name2:Name3:Name4:Name5
1:Bob:Romney:Hat:Alex:James
(as you can see Josh was excluded and Rolf was too low)
And since Rolf is alone and there are no one else left, he wont be put into a team and will be left unconfirmed...
I'm not really pro at mysql so I was stumped on this and at most was capable of organizing the whole thing by rank and that's it ._.
edit:
The terrible attempt I had at this:
<?php
$parse = mysql_query("SELECT MAX(rank) AS rank FROM users AND confirm='0'");
mysql_query("Insert into squad (nameone)values($parse)");
mysql_query("Update squad set confirm = '1' where name = $parse");
?>
Assuming confirm will have only either 1 or 0.
CREATE TABLE table2 (id INT PRIMARY KEY AUTO_INCREMENT, name varchar(255));
CREATE PROCEDURE rank()
BEGIN
DECLARE count INT DEFAULT 1;
WHILE count > 0 DO
UPDATE table1 SET Confirm=2 WHERE Confirm=0 ORDER BY Rank DESC LIMIT 5;
INSERT INTO table2 (SELECT GROUP_CONCAT(Name) FROM table1 WHERE Confirm=2);
UPDATE table1 SET Confirm=1 WHERE Confirm=2;
SELECT count(*) FROM table1 WHERE Confirm=0;
END WHILE;
END;
Call the procedure rank() when ever you want
CALL rank();
I have a table that is is sorted 1st by Reminder Date then ID
Table Looks like:
ID | remind_date
1 2011-01-23
2 2010-02-21
4 2011-04-04
5 2011-04-04
6 2009-05-04
I am using a PHP front end to move forward and back thur the records. I want to have forward and back buttons but i am running into a problem with the 2 reminder dates that are the same.
Just to note the ID's are NOT in order, they are here but in the actual database they are mixed up when sorting by reminder_date
The select statement i am using is: ($iid is the current record i am on)
SELECT id FROM myDB.reminders where remind_date > (SELECT remind_date FROM myDB.reminders where id=$iid) order by remind_date ASC LIMIT 1
So what happens when i get to the dates that are the same its skips over one because its asking for remind_date >.
If i use remind_date >= it returns the current record. My solution was then to use limit 2 and check via PHP to if the 1st record = my current ID, if it did use the next one. but what it there are 3 dates the same or 4 etc..
I also thought about using the ID field but since they are out of order i can't add in a ID > $iid.
Any ideas? it works great except for 2 dates that are the same.
You might be able to use this:
SELECT ID, remind_date
FROM
(
SELECT #prev_id := -1
) AS vars
STRAIGHT_JOIN
(
SELECT
ID,
remind_date,
#prev_id AS prev_id,
#prev_id := id
FROM myDB.reminders
ORDER BY remind_date, ID
) T1
WHERE prev_id = $iid
Here is a test of the above with your test data from your comment:
CREATE TABLE Table1 (ID INT NOT NULL, remind_date DATE NOT NULL);
INSERT INTO Table1 (ID, remind_date) VALUES
(45, '2011-01-14'),
(23, '2011-01-22'),
(48, '2011-01-23'),
(25, '2011-01-23'),
(63, '2011-02-19');
SELECT ID, remind_date
FROM
(
SELECT #prev_id := -1
) AS vars
STRAIGHT_JOIN
(
SELECT
ID,
remind_date,
#prev_id AS prev_id,
#prev_id := id
FROM table1
ORDER BY remind_date, ID
) T1
WHERE prev_id = 25
Result:
ID remind_date
48 2011-01-23
add a condition WHERE ID<>MY_LAST_ID. This can not work with triple and more same dates, so you can collect already taken ID's to array like (4,5,6) - see array_push(), implode it with "," to convert to a string (let's call it YOUR_IDS_STRING) and add to your query:
WHERE id NOT IN( YOUR_IDS_STRING )
And after each query make check, does date has changed and if it does - you can unset your array and start from begining (this is not neccesary, but gives you more performance, because YOUR_ID_STRING will be only that long as is need).
If your page is refreshing between queries, maybe try to push YOUR_ID_STRING in session variable, _GET or cookies, and simply concat next id's by operator .=
I used the code provided by Mark Byers and with small changes I adapted it to navigate in opposite directions (and to pass other columns too, not only the date and ID):
$results = $mysqli->query("SELECT * FROM (SELECT #prev_id := -1) AS vars STRAIGHT_JOIN (SELECT *, #prev_id AS prev_id, #prev_id := ID FROM my_table ORDER BY data, ID) T1 WHERE prev_id = ".$ID);
$results = $mysqli->query("SELECT * FROM (SELECT #next_id := 1) AS vars STRAIGHT_JOIN (SELECT *, #next_id AS next_id, #next_id := ID FROM my_table ORDER BY data DESC, ID DESC) T1 WHERE next_id = ".$ID);
I tested it on duplicate dates and it navigates well trough a list of records displayed with:
$results = $mysqli->query("SELECT * FROM my_table ORDER BY data DESC, ID DESC");
Hello i have a question on picking random entries from a database. I have 4 tables, products, bids and autobids, and users.
Products
-------
id 20,21,22,23,24(prime_key)
price...........
etc...........
users
-------
id(prim_key)
name user1,user2,user3
etc
bids
-------
product_id
user_id
created
autobids
--------
user_id
product_id
Now a multiple users can have an autobid on an product. So for the next bidder I want to select a random user from the autobid table
example of the query in language:
for each product in the autobid table I want a random user, which is not the last bidder.
On product 20 has user1,user2,user3 an autobidding.
On product 21 has user1,user2,user3 an autobidding
Then I want a resultset that looks for example like this
20 – user2
21 – user3
Just a random user. I tried miximg the GOUP BY (product_id) and making it RAND(), but I just can't get the right values from it. Now I am getting a random user, but all the values that go with it don't match.
Can someone please help me construct this query, I am using php and mysql
The first part of the solution is concerned with identifying the latest bid for each product: these eventually wind up in temporary table "latest_bid".
Then, we assign randon rank values to each autobid for each product - excluding the latest bid for each product. We then choose the highest rank value for each product, and then output the user_id and product_id of the autobids with those highest rank values.
create temporary table lastbids (product_id int not null,
created datetime not null,
primary key( product_id, created ) );
insert into lastbids
select product_id, max(created)
from bids
group by product_id;
create temporary table latest_bid ( user_id int not null,
product_id int not null,
primary key( user_id, product_id) );
insert into latest_bid
select product_id, user_id
from bids b
join lastbids lb on lb.product_id = b.product_id and lb.created = b.created;
create temporary table rank ( user_id int not null,
product_id int not null,
rank float not null,
primary key( product_id, rank ));
# "ignore" duplicates - it should not matter
# left join on latest_bid to exclude latest_bid for each product
insert ignore into rank
select user_id, product_id, rand()
from autobids a
left join latest_bid lb on a.user_id = lb.user_id and a.product_id = lb.product_id
where lb.user_id is null;
create temporary table choice
as select product_id,max(rank) choice
from rank group by product_id;
select user_id, res.product_id from rank res
join choice on res.product_id = choice.product_id and res.rank = choice.choice;
You can use the LIMIT statement in conjunction with server-side PREPARE.
Here is an example that selects a random row from the table mysql.help_category:
select #choice:= (rand() * count(*)) from mysql.help_category;
prepare rand_msg from 'select * from mysql.help_category limit ?,1';
execute rand_msg using #choice;
deallocate prepare rand_msg;
This will need refining to prevent #choice becoming zero, but the general idea works.
Alternatively, your application can construct the count itself by running the first select, and constructing the second select with a hard-coded limit value:
select count(*) from mysql.help_category;
# application then calculates limit value and constructs the select statement:
select * from mysql.help_category limit 5,1;