How can I not remove the last item in a table? - mysql

I have a table which must have minimum one item. How can I prevent to remove the last item?
For example, I have a table named USER, this table must contain at least one user. I can delete a user, but I cannot delete when the number of users is equal to one.

you may need to write sp like this.
CREATE DEFINER=`root`#`localhost` PROCEDURE `deleteuser`(userId INT)
BEGIN
IF EXISTS(SELECT * FROM USER WHERE Id<>userId) THEN
DELETE FROM USER WHERE Id=userId;
END IF;
END$$
DELIMITER ;
and you can call it.
call deleteuser(1);

How about:
DELETE FROM USER
WHERE ID = #ID
AND (SELECT COUNT(*) FROM USER AS t1) > 0

Try to use TRIGGERS Which will validate the number of rows before Delete query on that table.

Related

How to create a table that lists all the names in one table and counts the number of times it appears in another one?

I have to create a table named vecesCarcel which whenever I insert a name, it automatically adds another cell with the number of times the name appears in another table. So far I've tried with triggers this, but without result:
USE lordfarquaad;
CREATE TABLE IF NOT EXISTS vecesCarcel(
nombrePersonaje VARCHAR(10),
veces INTEGER(5) UNSIGNED)
ENGINE=InnoDB;
ALTER TABLE vecesCarcel
ADD CONSTRAINT vecesCarcelFK1 FOREIGN KEY(nombrePersonaje)
REFERENCES personajes(nombrePersonaje)
ON DELETE CASCADE ON UPDATE CASCADE;
USE lordfarquaad;
DELIMITER $$
CREATE PROCEDURE checkvecescarcel(IN nombre VARCHAR(10),OUT veces INT(5))
BEGIN
SET veces=(SELECT COUNT(*) FROM historiales WHERE nombrePersonaje=nombre);
END
$$
CREATE TRIGGER vecesCarcel_Insert BEFORE INSERT ON vecesCarcel FOR EACH ROW
BEGIN
CALL checkvecescarcel(NEW.nombrePersonaje,NEW.veces);
END;
$$
If you want to use a trigger, you have to set the new.veces-value inside the trigger:
CREATE TRIGGER vecesCarcel_Insert BEFORE INSERT ON vecesCarcel FOR EACH ROW
SET new.veces=(SELECT COUNT(*) FROM historiales
WHERE nombrePersonaje=NEW.nombrePersonaje);
You might want to create an on update-trigger, too (same code, so you can aswell put select count(*)... in a function and use set new.veces = myfnct(new.nombrepersonaje)).
But keep in mind your count will not update itself if you change anything in the table historiales (e.g. add another entry with the name in the list). So, depending on your setup, and if your historiales-table can change, or if you just might want to try a different approach, you can try a view:
create view vecesCarcelView as
select nombrePersonaje,
(select count(*)
from historiales
where vecesCarcel.nombrePersonaje=historiales.nombrePersonaje) as veces
from vecesCarcel;
(If you don't care so much about the order, you can do this with a left join and a group by too; and you could actually use the view with the whole personajes-table to display the count for all known names.)

how to set limit on table containing record

I am using mySQL
Is there any way to set limit of table record/row? I have table X and want to set limit of total records/rows on table, for example 2rows. So no one can insert third record in table. This table should not allow to insert third record.
I do not want to use Triggers.
You can do it this the user grants, so the user cant write into this table and you can create a separate User for administration this table.
seee Manual : https://mariadb.com/kb/en/mariadb/grant/
If you dont want to use triggers, you 'll have to check the number of rows inside your application (if any).
Create an AFTER INSERT trigger on the table. - it's the only way to do it.
create trigger TableLimit
on TableName
after insert
as
declare #countTableRows int
select #countTableRows = Count(*)
from TableName
if #countTableRows > 2
begin
rollback
end
go

Using a variable in a MySQL stored procedure

I need to clean up the users table and several related tables. So I create a variable that contains the userids and I want to use those values instead of using a sub-query for each delete statement.
I get a syntax error with this. What am I doing wrong?
DELIMITER $$
CREATE PROCEDURE `DBNAME`.`SP_PURGE_DISABLED_USERS` ()
BEGIN
select userid into #disabled_users from USERS where disabled=1;
delete from USER_ACTIVITY where userid in SELECT userid FROM #disabled_users;
delete from USER_PREFS where userid in SELECT userid FROM #disabled_users;
-- <snip> several other related tables to be cleaned up
delete from USERS where userid in SELECT userid FROM #disabled_users;
END
For one thing, at the end of your procedure you need to put your delimiter:
END$$
Then reset you're delimiter back to ;
DELIMITER ;
In the procedure, your delete statements don't make sense. I'd stop using the parameter to store the results of the select and an inner select:
delete from USER_ACTIVITY
WHERE userid in ( select userid from users where disabled=1 );
If you only have a realatively small set of disabled users to delete, you could use group concat and find in set:
DELIMITER $$
CREATE PROCEDURE `DBNAME`.`SP_PURGE_DISABLED_USERS` ()
BEGIN
select GROUP_CONCAT(userid) into #disabled_users from USERS where disabled=1;
delete from USER_ACTIVITY where FIND_IN_SET(userid, #disabled_users);
delete from USER_PREFS where FIND_IN_SET(userid, #disabled_users);
-- <snip> several other related tables to be cleaned up
delete from USERS where FIND_IN_SET(userid, #disabled_users);
END$$
DELIMITER ;
I wouldn't do this with many thousands of userid's though... there may be a limit to string length in a variable.
I decided to go with a temporary table. It cut the stored procedure execution time in half.
CREATE PROCEDURE `DBNAME`.`SP_PURGE_DISABLED_USERS` ()
BEGIN
create temporary table disabled_users
as (select userid from USERS where disabled=1);
delete from USER_ACTIVITY where userid in SELECT userid FROM disabled_users;
delete from USER_PREFS where userid in SELECT userid FROM disabled_users;
-- <snip> several other related tables to be cleaned up
delete from USERS where userid in SELECT userid FROM disabled_users;
drop table disabled_users;
END
Thanks to all who helped on this question.

MYSQL Stored Proc: How to delete a just updated record

I have two table Name: registeredList & deregisteredlist. Now when a user getting getting deregistered from "registeredlist" table then a trigger update his info to deregistration table and delete the record from registration table. On my below proc i can update it properly but can't delete the user from registered table. My proc:
DELIMITER $$
USE `abc_db`$$
DROP TRIGGER `UnsubscriberListTrigger`$$
CREATE
TRIGGER `UnsubscriberListTrigger` AFTER UPDATE ON `registeredlist` FOR EACH ROW
BEGIN
IF (old.SubscriberStatus='registered') THEN
INSERT INTO deregisteredlist(name,SubscriberStatus,DeRegistrationDate)
VALUES(old.name,'Deregistered',NOW());
DELETE from registeredlist where old.id=new.id;/???????/I am getting problem here
END IF;
END $$
DELIMITER ;
Thanks in advance.
I think all you need is to change WHERE in DELETE statement.
It should go like this:
DELETE from registeredlist where id=old.id; // (or new.id cause in this case old.id is equal to new.id)
... because you want to match it against id column.
UPDATE:
Another possibility is this:
- create AFTER INSERT TRIGGER on deregisteredlist which will do the DELETE in registeredlist. That way you shouldn't get that error.
Try this::
DELETE from registeredlist order by updateddat desc limit 1;

Mysql trigger issue (i think it's firing)

I have an issue with a trigger on a mysql database. I have a table such as follows:
id int not null auto_increment (PK)
parent_id int not null,
rank int not null
What I'm trying to do is use a trigger to update the rank to the next highest +10 when they have the same parent_id, but this doesn't seem to be working.
DELIMITER $$
DROP TRIGGER IF EXISTS after_insert $$
create trigger after_insert
after insert on mytable
FOR EACH row
BEGIN
IF EXISTS (SELECT rank FROM mytable WHERE parent_id = new.parent_id AND id != new.id ORDER BY rank DESC LIMIT 1) THEN
UPDATE mytable SET rank = 10
WHERE id = new.id;
ELSE
UPDATE mytable SET rank = 20
WHERE id = new.id;
END IF;
END
$$
I've tried setting the new rank to a variable and calling the update statement using that, and again it didn't work. I even created another table to log what values were being selected and that worked perfectly so I can't quite understand what's going on. Is it a case of, although the trigger is "AFTER INSERT" the insert hasn't actually happened so it can't update the row it's just inserted? Another reason I ask this is, I've even tried updating the rank to different values e.g 1 and 2 depending on which statement it goes to, but it always ends up being 0.
I think you're on the right track with this thought:
Is it a case of, although the trigger is "AFTER INSERT" the insert hasn't actually happened so it can't update the row it's just inserted?
From the FAQ:
B.5.9: Can triggers access tables?
A trigger can access both old and new data in its own table. A trigger can also affect other tables, but it is not permitted to modify a table that is already being used (for reading or writing) by the statement that invoked the function or trigger.
The documentation isn't clear that what you're doing won't work. OTOH, the documentation isn't clear that what you're trying to do will work either.
I think you'd be better off using a BEFORE INSERT trigger and setting NEW.rank in there. Then, the new row would have the right rank value when it is actually inserted into the table rather than patching it after. Also, you'd be able to simplify your existence check to just this:
EXISTS(SELECT rank FROM mytable WHERE parent_id = new.parent_id)
as NEW.id wouldn't have a useful value and the new row wouldn't be in the table anyway; the ORDER BY and LIMIT are also unnecessary as you're just checking if something exists so I took them out.
A BEFORE INSERT trigger seems to match your intent better anyway and that will give you correct data as soon as it is inserted into your table.
If you want the rank to be set +10 more than highest "brother's" rank, you could use:
DELIMITER $$
DROP TRIGGER IF EXISTS whatever $$
create trigger whatever
BEFORE INSERT ON mytable
FOR EACH row
BEGIN
SET NEW.rank = 10 + COALESCE(
( SELECT max(rank)
FROM mytable
WHERE parent_id = NEW.parent_id
), 0 ) ;
END
$$