Let's say I have two tables:
info(id PRIMARY KEY, opendate NOT NULL, closedate)
fileinfo(fileno PRIMARY KEY, id FOREIGN KEY REFERENCES info.id)
I would like to allow new entries into fileinfo only if the corresponding value of info.closedate is null. Is there a way to do that?
You can attach a trigger to the fileinfo table, to run on INSERT, which looks up the closedate on info, and throws an error if it's not null.
EDIT: Added example of a SQLServer trigger which would do the same thing. Edit as MySQL syntax requires.
CREATE TRIGGER InsertFileInfo
ON fileinfo
AFTER INSERT
AS
BEGIN
declare #closedate DateTime ;
select #closedate = closedate from info where id in (select id from new);
if #closedate is not null
begin
raiserror ('CloseDate is not null', 16, 1);
end
END
Related
I would like to add a constraint that will check values from related table.
I have 3 tables:
CREATE TABLE somethink_usr_rel (
user_id BIGINT NOT NULL,
stomethink_id BIGINT NOT NULL
);
CREATE TABLE usr (
id BIGINT NOT NULL,
role_id BIGINT NOT NULL
);
CREATE TABLE role (
id BIGINT NOT NULL,
type BIGINT NOT NULL
);
(If you want me to put constraint with FK let me know.)
I want to add a constraint to somethink_usr_rel that checks type in role ("two tables away"), e.g.:
ALTER TABLE somethink_usr_rel
ADD CONSTRAINT CH_sm_usr_type_check
CHECK (usr.role.type = 'SOME_ENUM');
I tried to do this with JOINs but didn't succeed. Any idea how to achieve it?
CHECK constraints cannot currently reference other tables. The manual:
Currently, CHECK expressions cannot contain subqueries nor refer to
variables other than columns of the current row.
One way is to use a trigger like demonstrated by #Wolph.
A clean solution without triggers: add redundant columns and include them in FOREIGN KEY constraints, which are the first choice to enforce referential integrity. Related answer on dba.SE with detailed instructions:
Enforcing constraints “two tables away”
Another option would be to "fake" an IMMUTABLE function doing the check and use that in a CHECK constraint. Postgres will allow this, but be aware of possible caveats. Best make that a NOT VALID constraint. See:
Disable all constraints and table checks while restoring a dump
A CHECK constraint is not an option if you need joins. You can create a trigger which raises an error instead.
Have a look at this example: http://www.postgresql.org/docs/9.1/static/plpgsql-trigger.html#PLPGSQL-TRIGGER-EXAMPLE
CREATE TABLE emp (
empname text,
salary integer,
last_date timestamp,
last_user text
);
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
BEGIN
-- Check that empname and salary are given
IF NEW.empname IS NULL THEN
RAISE EXCEPTION 'empname cannot be null';
END IF;
IF NEW.salary IS NULL THEN
RAISE EXCEPTION '% cannot have null salary', NEW.empname;
END IF;
-- Who works for us when she must pay for it?
IF NEW.salary < 0 THEN
RAISE EXCEPTION '% cannot have a negative salary', NEW.empname;
END IF;
-- Remember who changed the payroll when
NEW.last_date := current_timestamp;
NEW.last_user := current_user;
RETURN NEW;
END;
$emp_stamp$ LANGUAGE plpgsql;
CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
...i did it so (nazwa=user name, firma = company name) :
CREATE TABLE users
(
id bigserial CONSTRAINT firstkey PRIMARY KEY,
nazwa character varying(20),
firma character varying(50)
);
CREATE TABLE test
(
id bigserial CONSTRAINT firstkey PRIMARY KEY,
firma character varying(50),
towar character varying(20),
nazwisko character varying(20)
);
ALTER TABLE public.test ENABLE ROW LEVEL SECURITY;
CREATE OR REPLACE FUNCTION whoIAM3() RETURNS varchar(50) as $$
declare
result varchar(50);
BEGIN
select into result users.firma from users where users.nazwa = current_user;
return result;
END;
$$ LANGUAGE plpgsql;
CREATE POLICY user_policy ON public.test
USING (firma = whoIAM3());
CREATE FUNCTION test_trigger_function()
RETURNS trigger AS $$
BEGIN
NEW.firma:=whoIam3();
return NEW;
END
$$ LANGUAGE 'plpgsql'
CREATE TRIGGER test_trigger_insert BEFORE INSERT ON test FOR EACH ROW EXECUTE PROCEDURE test_trigger_function();
I am trying to create a Table in MySQL with id as bigint not null auto_increment . This is the structure of MySQL table
create table test_profile (
id bigint not null auto_increment,
type integer not null,
type2 integer generated always as (case when type = 0 then id else type end),
primary key (id),
constraint fk_profile_to foreign key(test_profile_1) references test_profile_1(id) on delete cascade
);
I have run this table on MySQL workbench , I am getting the following error
Error Code: 3109. Generated column 'type2' cannot refer to auto-increment column.
Any idea to solve this type of error ? Any alternative methods or suggestions ?
Use trigger instead to fulfill your requirement as generated column can't refer auto increment column . This is the one good alternative for performing such a task. Below is insert trigger and I think you have to create AFTER UPDATE trigger also
DELIMITER $$
CREATE TRIGGER TRGUpdateTestProfile
AFTER INSERT ON test_profile
FOR EACH ROW
BEGIN
UPDATE test_profile SET Type2 = case when type = 0 then new.id else new.type end
WHERE id = new.id;
END$$
DELIMITER;
I have multiple tables in this database; two of which are involved with this trigger
create table shipment_item(
shipmentID int not null,
shipmentItemID int not null,
purchaseID int not null,
insuredValue decimal(5,2) not null,
constraint shipment_ItemPK primary key(shipmentID, shipmentItemID),
constraint shipmentFK foreign key(shipmentID)
references shipment(shipmentID)
on delete cascade,
constraint purchaseFK foreign key(purchaseID)
references purchase(purchaseID)
);
create table purchase(
purchaseID int not null auto_increment,
storeID int not null,
purchaseDate date not null,
description char(30) not null,
category char(30) not null,
price decimal(5,2) not null,
constraint purchasePK primary key(purchaseID),
constraint storeFK foreign key(storeID)
references store(storeID)
);
I'm trying to implement a trigger in my MySQL database. That trigger looks like this
DELIMITER //
CREATE TRIGGER checkInsuranceTrigger
BEFORE INSERT ON shipment_item
FOR EACH ROW BEGIN
IF(shipment_item.insuredValue <= purchase.price) THEN
SET NEW.insuredValue = purchase.price;
END IF;
END
//
DELIMITER ;
When I implement this trigger and then try to insert data into the shipment_item table I get the following error
Error Code 1109: Unknown Table 'shipment_item' in field list
Reference the column in the row being inserted with the NEW keyword, like you did on the SET statement.
To reference values from rows in other tables, you need a SQL statement, in your case, looks like you want a SELECT.
For example (following the outline of the logic in your trigger), something like this:
BEGIN
-- local variable
DECLARE ln_purchase_price DECIMAL(5,2);
-- populate local variable (this is just an example of one way to do this)
SELECT p.price
INTO ln_purchase_price
FROM purchase p
WHERE p.purchaseID = NEW.purchaseID
LIMIT 1;
-- compare value from row to local variable
IF (NEW.insuredValue <= ln_purchase_price) THEN
SET NEW.insuredValue = ln_purchase_price;
END IF;
May I suggest verifying that the table really exists in the same database as the trigger itself?
I need to create MySQL trigger that would log user ID on delete table row statement which must fit in one query, since I'm using PHP PDO. This is what I've come up so far:
I need the way to pass user ID in the delete query even though it is irrelevant to delete action to be performed:
Normally the query would look like this:
DELETE FROM mytable WHERE mytable.RowID = :rowID
If I could use multiple queries in my statement, I would do it like this:
SET #userID := :userID;
DELETE FROM mytable WHERE mytable.RowID = :rowID;
This way the variable #userID would be set before trigger event fires and it can use it. However since I need to squeeze my delete statement in one query, so I came up with this:
DELETE FROM mytable
WHERE CASE
WHEN #userID := :userID
THEN mytable.RowID = :rowID
ELSE mytable.RowID IS NULL
END
Just a note: RowID will never be null since it's the primary key. Now I have to create a delete trigger to log the user ID to the audit table, however I suppose that in this case trigger will be fired before the delete query itself which means that #userID variable will not be created? This was my idea of passing it as a value to the trigger.
I feel like I'm close to the solution, but this issue is a blocker. How to pass user ID value to the trigger without having multiple queries in the statement? Any thoughts, suggestions?
You can use NEW / OLD mysql trigger extensions. Reference: http://dev.mysql.com/doc/refman/5.0/en/trigger-syntax.html
Here is a sample code :
drop table `project`;
drop table `projectDEL`;
CREATE TABLE `project` (
`proj_id` int(11) NOT NULL AUTO_INCREMENT,
`proj_name` varchar(30) NOT NULL,
`Proj_Type` varchar(30) NOT NULL,
PRIMARY KEY (`proj_id`)
);
CREATE TABLE `projectDEL` (
`proj_id` int(11) NOT NULL AUTO_INCREMENT,
`proj_name` varchar(30) NOT NULL,
`Proj_Type` varchar(30) NOT NULL,
PRIMARY KEY (`proj_id`)
);
INSERT INTO `project` (`proj_id`, `proj_name`, `Proj_Type`) VALUES
(1, 'admin1', 'admin1'),
(2, 'admin2', 'admin2');
delimiter $
CREATE TRIGGER `uProjectDelete` BEFORE DELETE ON project
FOR EACH ROW BEGIN
INSERT INTO projectDEL SELECT * FROM project WHERE proj_id = OLD.proj_id;
END;$
delimiter ;
DELETE FROM project WHERE proj_id = 1;
SELECT * FROM project;
SELECT * FROM projectDEL;
I have a table, which includes an ENUM field. I would like for a particular value of ENUM to require uniqueness with the reference ID column. So let's say I have this:
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`type` ENUM('single','multi') NOT NULL,
`refid` INT UNSIGNED NOT NULL,
`extra` TEXT,
PRIMARY KEY (`id`)
I want (type,refid) to be a unique key, but only if type is single. This can't be done with conventional keys, so I figured I would use a Trigger to detect insertion of a row, check if type='single', look for a row with type='single' and refid=new.refid, and throw a duplicate entry error if one is found.
I'm using MySQL 5.5, so SIGNAL SQLSTATE is available to me. Can I use this to fire a Duplicate Key error in order to process the ON DUPLICATE KEY UPDATE part of the query, and if so, how?
As an alternative, I could update the row in the Trigger and return a generic error condition, but I think it would be nicer (or at least more intuitive) to have ON DUPLICATE KEY UPDATE work.
REPLACE INTO. Derp! Forgot all about that.
Try below trigger. I am not that good in writing triggers. I have not executed the code below. You can use this as a prototype.
CREATE TRIGGER checkDuplicateEntry
BEFORE INSERT OR UPDATE OF type, ref_id ON employees
DECLARE #duplicateCount INT;
FOR EACH ROW
IF ( new.type <> 'single' )
BEGIN
#duplicateCount = count(*) from yourTableName where type = 'single' AND refid = new.refid
END;
IF ( duplicateCount > 0 )
BEGIN
SIGNAL SQLSTATE VALUE '99999'
SET MESSAGE_TEXT = 'Duplicate Entry';
END