Ensuring String inequality in MySQL - mysql

I have a MySQL table called flights that includes fields called origin and destination which are the airport codes referenced from the airports table and which i have defined as CHAR(3). I want to be able to insert records where for obvious reasons the values in the origin and departure columns cannot be the same.
How do i accomplish this with an INSERT INTO TABLE SQL statement?

The only way you can do this in MySQL is using a trigger.
Other databases support a check constraint where you can say check (origin <> destination). MySQL accepts this syntax but unfortunately does not enforce the constraint.
You can also do this at the application layer.

Create a trigger:
CREATE TRIGGER `travels_before_insert` BEFORE INSERT ON `travels` FOR EACH ROW BEGIN
DECLARE msg VARCHAR(255);
IF NEW.source=NEW.destination THEN
set msg = "Error: You can't have same source and destination";
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;
END IF;
END;
What it does is prevent the insert from occuring if source and destination are the same.

Related

How to add a integrity check on mySQL Workbench

I'm new to mySQL and I'd like to add a integrity check (or constraint? Sorry I'm italian) in my database.
Let me explain: I have two tables
Workshop (location, numPlaces, numOperations)
Operation (idoperation, workLocation, ...)
numPlaces represents the maximum number of operations the workshop can afford. I created a trigger that everytime I insert a new record in Operation, the numOperations of Workshop referred to that specific location is increased by 1.
Now what I'd like to do is: when numOperations = numPlaces, if I try to insert a new record to Operation, the system must tell me that I can't. Basically, it can't be possible that numOperations > numPlaces
Is there a way to achieve that? Sorry if I can't provide codes, but I literally have no idea where should I go to create these types of CHECKS. Hope you can help me!
For this to work, you must have set the workshop with the correct number of places.
And you should have a routine, that diminishes the number of operations so that you can enter new operation in one workshop
CREATE TABLE Workshop
(location Text, numPlaces int , numOperations int
)
INSERT INTO Workshop VALUES ('A',9,8)
CREATE TABLE Operation (idoperation int, workLocation Text)
CREATE TRIGGER before_Operation_insert
BEFORE INSERT
ON Operation FOR EACH ROW
BEGIN
DECLARE Placescount_ INT;
DECLARE Operationscount_ INT;
SELECT numPlaces, numOperations
INTO Placescount_,Operationscount_
FROM Workshop WHERE location = NEW.workLocation;
IF Placescount_ < Operationscount_ THEN
UPDATE Workshop
SET numOperations = numOperations + 1 WHERE location=new.workLocation ;
ELSE
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Maximum Number of Operarations reached in location ';
END IF;
END
INSERT INTO Operation VALUES (1,'A')
Maximum Number of Operarations reached in location
db<>fiddle here

MySQl I need to make a column unique only for certain values of another column

I have two columns Name,IsDelete in a table T
There can only be unique names for IsDelete=0
For IsDelete=1, there can be duplicate names.
I'm using this query
CREATE UNIQUE INDEX ix ON T(Name) WHERE IsDelete = 0;
But I'm getting the error,
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE IsDeleted = 0 at line 1
How can I use triggers to solve this?
Unique indices must have references to ALL RECORDS.
They cannot be conditional creation of unique index construction.
The requirement you set could be covered by another table structure where the deleted or not is not part of the record.
You must redesign the data to use a master table with unique IDs and alter the current to link to the master table.
It is a basic theoretical lesson in data normalisation.
Yeah, so I got a trigger that would check for the condition to be true.
DELIMITER $$
CREATE TRIGGER testing4
BEFORE INSERT ON biomitra_user
FOR EACH ROW BEGIN
IF EXISTS (select mobile_number from biomitra_user where is_deleted=0) THEN
SIGNAL SQLSTATE '02000' SET MESSAGE_TEXT = 'Duplicate';
else
set new.mobile_number=new.mobile_number;
END IF;
END$$
DELIMITER ;
This is working fine

"Not include" Constraint?

Thanks for reading this.
I have tables like this in MySQL:
Device table has a list of name. And ReservedName table has a list of "reserved" name list.
As you may see, my design concept is to make Name value of Device table SHOULD NOT one of Name in ReservedName.
I could easily implement this relation by add a few SQL statement when I do INSERT operation to Device table. But I am wondering if there is something like "Not one of" constraint in the table schema? Maybe opposite meaning of FOREIGN KEY? It is also welcome if there is any other way to make that relationship.
You can create a BEFORE INSERT triggers which can either cause an error or set the field to its default value when the requirements of the data are not met.
In your case you can create a trigger, which will raise error, if your validation fails, something like following:
CREATE TRIGGER `validate_before_insert` BEFORE INSERT ON `Device`
FOR EACH ROW
BEGIN
IF EXISTS (SELECT* FROM ReservedName WHERE Name = new.Name) THEN
SIGNAL SQLSTATE '12345'
SET MESSAGE_TEXT := 'check constraint on Device.Name failed';
END IF;
END
You can read more about MySQL triggeres in documentation.

Mysql dropping inserts with triggers

Using mysql 5.6. I have two tables. One has a whitelist of hashes. When I insert a new row into the other table, I want to first compare the hash in the insert statement to the whitelist. If it's in the whitelist, I don't want to do the insert (less data to plow through later). The inserts are generated from another program and are text files with sql statements.
I've been playing with triggers, and almost have it working:
CREATE TRIGGER `Filelist` BEFORE INSERT ON `filelist`
FOR EACH ROW BEGIN IF(
SELECT count( md5hash ) FROM whitelist WHERE md5hash = new.hash ) >0
THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Can not have duplicates';
END IF ;
END
But there's a problem. The Signal throwing up the error stops the import. I want to skip that line, not stop the whole import.
Some searching didn't find any way to silently skip the import.
My next idea was to create a duplicate table definition, and redirect the insert to that dup table. But the old and new don't seem to apply to table names.
Other then adding an ignore column to my table then doing a mass drop based on that column after the import, is there any way to achieve my goal? I'm having problems with this too [Ignore is a tinyint(1)]:
DELIMITER $$
CREATE TRIGGER whitelisted
BEFORE INSERT ON filelist
FOR EACH ROW BEGIN
IF (select count(md5hash) from whitelist where md5hash=new.hash) > 0 THEN
SET Ignore = true;
END IF;
END$$
/* This is now "END$$" not "END;" */
/* Reset the delimiter back to ";" */
DELIMITER ;
#1064 - You have an error in your SQL syntax; check the manual that corresponds to
your MySQL server version for the right syntax to use near ') THEN SET Ignore = true;
END IF; END' at line 4
Any suggestions? I've also tried
SET Ignore = 1;
SET Ignore = '1';
SET new.Ignore = {all of the above};
I'm not sure if I follow this specification:
I have two tables. One has a whitelist of hashes. When I insert a new row into the other table, I want to first compare the hash in the insert statement to the whitelist. If it's in the whitelist, I don't want to do the insert
My first attempt would be like this:
INSERT INTO filelist (filename, hash)
SELECT "myfile", "ABCD" FROM DUAL
WHERE NOT EXISTS(
SELECT md5hash FROM whitelist where md5hash = "ABCD"
);
I don't think you need triggers for this at all unless there are missing details in your requirements.
I take it you're doing some kind of ON INSERT-trigger.
You need to add the following statement to your trigger to make it work as wanted:
FOR EACH ROW
This will make the trigger execute once on every row.

Trigger to silently ignore/delete duplicate entries on INSERT

I have the following table:
T(ID primary key, A, B)
I want to have pair (A, B) unique but I don't want to have constraint unique(A,B) on them because it will give error on insert.
Instead I want MySQL to silently ignore such inserts.
I can't use "insert on duplicate keys ignore" because I can't control client's queries.
So, can I build such trigger? Or maybe there is some constraint that allows silent ignore?
Edit: I dug around and I think I want something like SQLite's "Raise Ignore" statement.
Before mysql 5.5. it wasn't possible to stop an insert inside a trigger. There where some ugly work arounds but nothing I would recommend. Since 5.5 you can use SIGNAL to do it.
delimiter //
drop trigger if exists aborting_trigger //
create trigger aborting_trigger before insert on t
for each row
begin
set #found := false;
select true into #found from t where a=new.a and b=new.b;
if #found then
signal sqlstate '45000' set message_text = 'duplicate insert';
end if;
end //
delimiter ;
Add a unique key (A,B) and use INSERT statement with an IGNORE keyword.
From the reference - If you use the IGNORE keyword, errors that occur while executing the INSERT statement are treated as warnings instead.
INSERT Syntax.