How can I limit in MySQL maximum rows for the same "user" value?
For example, I have table with columns
id | user | data
and I would like to limit maximum rows count to 5 for each user (the same "user" value).
My idea is to use transactions (InnoDB):
start transaction
insert row with user = "XXX"
count rows, where user = "XXX"
if count < 5 commit else rollback
Is my idea good or exist also another (better) solution?
I think that it's ok, You may want to make a
select count(1) from table where user='XXX'
and check the count before performing the insert.
This could be done by using special "dual" table:
INSERT INTO table (id, user, data)
SELECT 1, 'XXX', 'somedata'
FROM dual
WHERE NOT EXISTS (
SELECT user
FROM t
WHERE user = 'XXX'
GROUP BY user
HAVING COUNT(*) >= 5
)
Related
I have a table with pre-populated data that looks similar to this:
Id
giftCode
userId
1
AGiftCode
42342
2
AnotherCode
NULL
3
AnotherOne
NULL
4
Code
NULL
5
Code2
NULL
6
Code3
NULL
Multiple users are simultaneously assigned to the pre-populated data at certain times, and I am currently achieving this using the following query multiple times:
UPDATE table SET userId = "xxxxx" WHERE userId is NULL LIMIT 1
Is there a way to do the same thing, but with a single UPDATE statement to insert x number of userId's into the next x number of open rows?
Only the userIds to insert and the number of userIds to be inserted is known at the point of updating.
One approach uses SELECT ... FOR UPDATE:
SELECT giftCode FROM yourTable WHERE userId IS NULL LIMIT 1 FOR UPDATE;
UPDATE yourTable SET userId = 'xxxxx' WHERE giftCode = 'code from above';
Below is the table i am trying to write a query for to add new rows for every user.
My question is how do i add a new row for every user? Which means for userId 2 I add AccId 4 and similarly for 7 and 8. Since there is no concept of for loop in sql, do i make use of while? If so, how to loop through the userIds since the IDs are not in equal increments?
something like this maybe:
Insert Into mytable (UserID, AccID)
Select UserID, max(accId)+1
From MyTable
Group By UserID
You can re-run it every time, you will create the next value.
Untested on a MySql server:
INSERT INTO MyTable ( ID, AccId )
SELECT MyValues.ID, MyValues.Espr1
FROM (SELECT MyTable.ID, Max([AccId]+1) AS Espr1
FROM MyTable
GROUP BY MyTable.ID) AS MyValues;
Basically we prefetch Id a AccId grouping the values of Id and grabbing the Max of AccId.
Then we add these rows to the main table. Repeating the query we will add the value 5 (AccId) and so on, always adding 1
Table structure
------------
Transaction
------------
id INT PrimaryKey
user_id INT ForeignKey
amount INT
------------
User
------------
id INT PrimaryKey
number INT
Transaction table contains multiple rows for each user, number of rows is stored in User.number (which is not same for every user)
Due to some bug in the program some extra rows has been created in Transaction table without increment User.number
Now I have to remove those extra rows from Transaction table.
As far as I know, to remove last 10 rows in Transaction table, I can run
DELETE * from Transaction ORDER BY id DESC LIMIT 10;
Is there any way to delete variable number of rows for different users in single SQL query?
You can do that by generating a SQL script to remove the additional transactions:
You should be able to find the users with:
SELECT user.id AS user_id, COUNT(transaction.id)-user.number AS num_trans FROM user, transaction WHERE user.id=transaction.user_id GROUP BY user.id, user.number HAVING user.number < COUNT(transaction.id)
Create a view from this select statement:
CREATE VIEW invalidusers AS
SELECT user.id AS user_id, COUNT(transaction.id)-user.number AS num_trans FROM user, transaction WHERE user.id=transaction.user_id GROUP BY user.id, user.number HAVING user.number < COUNT(transaction.id)
Check the output from this view.
Now select a script to execute from this view:
SELECT CONCAT('DELETE * FROM transaction WHERE user_id=', CONVERT(user_id, CHAR), ' ORDER BY id DESC LIMIT ', CONVERT(num_trans, CHAR), ';') AS CMD from invalidusers
The last command generates the script you can run to remove the transaction for all users.
First we start with empty table
rows = 0
Second we insert random rows let say 3400
rows = 3400
For the third time i count how many rows are in the table, then insert the new rows and after that delete rows <= from the count.
This logic only work for the first time. If that repeat the count will always be 3400 but the id will increase so it will not delete the rows
I cant use last inserted ID since the rows are random and I dont how many it will load.
// Update
"SELECT count(*) from table" - the total count so far
"INSERT INTO tab_videos_watched (id , name) values (id , name)" - this is random can be 3400 or 5060 or 1200
"DELETE FROM table WHERE idtable <= $table_count"
If id is auto incremented, then you should use like:
select max(id) from my_table;
Read this maxId into a variable and then use when issued a delete query like:
delete from my_table where id <= ?;
Replace query parameter with the last found maxId value.
Alternatively you can define a column last_inserted as datetime type.
Before next insertions, select it into a local variable.
select max(last_inserted) as 'last_inserted' from my_table;
And after insertions are made, use the last_inserted to delete records.
delete from my_table where last_inserted <= ?;
Replace query parameter with the last found last_inserted value.
How can I store only 10 rows in a MySQL table? The older rows should be deleted when a new row is added but only once the table has 10 rows.
Please help me
You could achieve this with an after insert trigger, delete the row where it is min date. e.g. DELETE FROM myTable WHERE myTimestamp = (SELECT MIN(myTimestamp) FROM myTable) but that could in theory delete multiple rows, depending on the granularity of your updates.
You could have an incrementing sequence, and always just delete the min of that sequence.
The question is why you'd want to do this though? It's a slightly unusual requirement.
A basic example (not validated/executed, I don't have mySQL on this particular machine) would look something like.
CREATE TRIGGER CycleOldPasswords AFTER INSERT ON UserPasswords FOR EACH ROW
set #mycount = SELECT COUNT(*) FROM UserPasswords up where up.UserId = NEW.UserId;
if myCount >= 10 THEN
DELETE FROM UserPasswords up where up.Timestamp = (SELECT min(upa Timestamp) FROM UserPasswords upa WHERE NEW.UserId = upa.UserId) AND NEW.UserId = up.UserId;
END
END;
You can retrieve the last inserted id when your first row is inserted, and store it in a variable. When 10 rows are inserted, delete the row having id < id of the first inserted record. Please try it.
first of all insert all values using your insert query
and then run this query
delete from table_name where (cond) order by id desc limit 10
must specify an id or time in one column