I have a problem inserting values into a Class table.
I want to write a trigger to prevent happening "an instructor teaches in different class_Id at the same time".
How can I do this?
CREATE TABLE Class
(
Class_ID BIGINT,
c_InstrumentID BIGINT NOT NULL,
c_StudentID BIGINT,
c_InstructorID BIGINT NOT NULL,
c_InstituteId BIGINT NOT NULL,
c_TermSeason NVARCHAR(10),
c_TermYear INT,
c_TimeOfClass TIME NOT NULL,
c_DayOfClass NVARCHAR(30),
c_Eligibility INT,
c_RemainingSession INT,
CONSTRAINT cons_Season
CHECK(c_TermSeason IN ('Spring', 'Summer', 'Fall', 'Winter')),
CONSTRAINT cons_TimeClass
CHECK(c_TimeOfClass BETWEEN '08:30:00' AND '20:30:00'),
CONSTRAINT cons_RemainSession
CHECK (c_RemainingSession BETWEEN 0 AND 12),
FOREIGN KEY(c_InstrumentID)
REFERENCES Instrument(Instrument_ID) ON DELETE NO ACTION,
FOREIGN KEY(c_StudentID)
REFERENCES Student(Student_ID) ON DELETE NO ACTION,
FOREIGN KEY(c_InstructorID)
REFERENCES Instructor(Instructor_ID) ON DELETE NO ACTION,
FOREIGN KEY(c_InstituteId)
REFERENCES Institute(Institute_ID) ON DELETE NO ACTION,
PRIMARY KEY (Class_ID)
)
This is the trigger which I've created:
CREATE OR ALTER TRIGGER One_InstructorDuplicate
ON Class
AFTER INSERT
AS
BEGIN
IF (NOT EXISTS (SELECT *
FROM Class C, ((SELECT * FROM CLASS)
EXCEPT (SELECT * FROM inserted)) AS newC
WHERE newC.c_InstructorID = C.c_InstructorID
AND newC.c_DayOfClass != C.c_DayOfClass
AND newC.c_TermSeason != C.c_TermSeason
AND newC.c_TermYear != C.c_TermYear
AND newC.c_TimeOfClass != C.c_TimeOfClass))
ROLLBACK TRAN
END;
Use inserted and JOIN to the Class table. Check for existence of rows in table that matches your requirement (c_DayOfClass, c_TermSeason etc)
CREATE OR ALTER TRIGGER One_InstructorDuplicate
ON Class
AFTER INSERT
AS
BEGIN
IF EXISTS
(
SELECT *
FROM inserted i
INNER JOIN Class c ON i.c_InstructorID = c.c_InstructorID
WHERE i.Class_ID <> c.Class_ID
AND i.c_DayOfClass = c.c_DayOfClass
AND i.c_TermSeason = c.c_TermSeason
AND i.c_TermYear = c.c_TermYear
AND i.c_TimeOfClass = c.c_TimeOfClass
)
BEGIN
ROLLBACK TRAN
END
END;
Related
THIS is what i try and error
postgres=# INSERT INTO cs222p_interchange.Ad(ad_id, plan, content, pic_num, item_id, seller_user_id, placed_date)
postgres-# VALUES ('ADT32457', 'Gold', 'New games available!', 1, 'F7E1N', '4Z5VC', '2022-11-06');
ERROR: record "new" has no field "user_id"
CONTEXT: SQL statement "INSERT INTO TargetedAds(ad_id, user_id)
SELECT NEW.ad_id, NEW.user_id WHERE (
SELECT category
FROM cs222p_interchange.item i
JOIN cs222p_interchange.ad a ON i.item_id = a.item_id
WHERE ad_id = NEW.ad_id AND (buyer_user_id = NEW.user_id OR seller_user_id = NEW.user_id) )
LIKE (
SELECT category
FROM cs222p_interchange.User u
JOIN cs222p_interchange.Categories c ON u.user_id = c.user_id
WHERE user_id = NEW.user_id)
ON CONFLICT DO NOTHING"
PL/pgSQL function addad() line 1 at SQL statement
This is the trigger
CREATE FUNCTION AddAd() RETURNS Trigger AS
$$
BEGIN
INSERT INTO TargetedAds(ad_id, user_id)
SELECT NEW.ad_id, NEW.user_id
WHERE (
SELECT *
FROM cs222p_interchange.item i
JOIN cs222p_interchange.ad a ON i.item_id = a.item_id
WHERE ad_id = NEW.ad_id AND (buyer_user_id = NEW.user_id OR seller_user_id = NEW.user_id) )
= (
SELECT category
FROM cs222p_interchange.User u
JOIN cs222p_interchange.Categories c ON u.user_id = c.user_id
WHERE user_id = NEW.user_id)
ON CONFLICT DO NOTHING;
RETURN NEW;
END;
$$
LANGUAGE PLPGSQL;
CREATE TRIGGER TargetedAdsLogger AFTER INSERT ON cs222p_interchange.Ad FOR EACH ROW EXECUTE FUNCTION AddAd();
This is the Table
CREATE TABLE TargetedAds(
ad_id text,
user_id text,
PRIMARY KEY (ad_id, user_id),
FOREIGN KEY (ad_id) REFERENCES cs222p_interchange.Ad
(ad_id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES cs222p_interchange.Seller(user_id) ON DELETE CASCADE
);
This is what i need to insert
INSERT INTO cs222p_interchange.Ad(ad_id, plan, content, pic_num, item_id, seller_user_id, placed_date)
VALUES ('ADT32457', 'Gold', 'New games available!', 1, 'F7E1N', '4Z5VC', '2022-11-06');
This is the definition of the Ad table:
CREATE TABLE cs222p_interchange.Ad(
ad_id text NOT NULL,
plan text NOT NULL ,
content text ,
pic_num int NOT NULL,
item_id text NOT NULL,
seller_user_id text NOT NULL,
placed_date date NOT NULL,
PRIMARY KEY (ad_id),
FOREIGN KEY(item_id) REFERENCES cs222p_interchange.Item(item_id) ON DELETE CASCADE,
FOREIGN KEY(pic_num, item_id) REFERENCES cs222p_interchange.Picture(pic_num, item_id) ON DELETE CASCADE,
FOREIGN KEY(seller_user_id) REFERENCES cs222p_interchange.Seller(user_id) ON DELETE CASCADE
);
I have checked multiple times and all of my tables and columns are existing.
I am trying to create a trigger that checks if the faculty member to be added to the assigned table will is already on the qualified table for a specified class. Perhaps this is a tedious method. Nevertheless, I'd still like to know what I'm doing wrong. The following is my code with created the created tables and the trigger being the last part of the code:
CODE:
CREATE TABLE Faculty (
FId varchar(10),
FName varchar(20),
CONSTRAINT Faculty_ID_pk PRIMARY KEY(FId)
);
CREATE TABLE Course (
CId varchar(10),
CName varchar(20),
CONSTRAINT Course_ID_pk PRIMARY KEY(CId)
);
CREATE TABLE Qualify (
QDate DATE,
FId varchar(10),
CId varchar(10),
CONSTRAINT Qualifying_date CHECK(QDate >= TO_DATE('2020-08-24', 'YYYY-MM-DD')),
CONSTRAINT Qualify_FID_fk FOREIGN KEY(FId) REFERENCES Faculty(FId),
CONSTRAINT Qualify_CID_fk FOREIGN KEY(CId) REFERENCES Course(CId)
);
CREATE TABLE Assign (
ADate DATE,
FId varchar(10),
CId varchar(10),
CONSTRAINT Qualifying_check CHECK(ADate > TO_DATE('2020-08-24', 'YYYY-MM-DD')),
CONSTRAINT Assign_FID_fk FOREIGN KEY(FId) REFERENCES Faculty(FId),
CONSTRAINT Assign_CID_fk FOREIGN KEY(CId) REFERENCES Course(CId)
);
CREATE OR REPLACE TRIGGER Check_If_Qualified
BEFORE INSERT ON Assign
FOR EACH ROW
DECLARE
v_facNum number;
BEGIN
SELECT f.FId
into v_facNum
from Faculty f
where f.facnum = :new.fid;
END;
However, I keep receiving an error saying:
Error at line 7: PLS-00225: subprogram or cursor 'F' reference is out of scope
v_facNum number;
BEGIN
SELECT f.FId
into v_facNum
from Faculty f
Does anyone know what could be wrong?
There are lots of issues in your code. You can check the count of records into FACULTY table and use that count for whatever logic you want.
CREATE OR REPLACE TRIGGER CHECK_IF_QUALIFIED
BEFORE INSERT ON ASSIGN
FOR EACH ROW
DECLARE
CNT NUMBER;
BEGIN
SELECT COUNT(1)
INTO CNT
FROM FACULTY
WHERE FACNUM = :NEW.FID;
END;
/
That would be something like this (sample tables are really just a sample; they are here to make the trigger compile):
SQL> create table assign (fid number);
Table created.
SQL> create table faculty (facnum number, fid number);
Table created.
SQL> CREATE OR REPLACE TRIGGER Check_If_Qualified
2 BEFORE INSERT ON Assign
3 FOR EACH ROW
4 DECLARE
5 v_facNum number;
6 BEGIN
7 SELECT f.FId
8 into v_facNum
9 from Faculty f
10 where f.facnum = :new.fid;
11
12 -- now do something with v_facNum
13 END;
14 /
Trigger created.
SQL>
I have 2 tables tlbinvoice and tblRel_Inv_Course in which InvoiceID is the foreign key. When I tried to delete a row from the Invoice table, I get an error
Cannot delete foreign key constraint
Below are the 2 queries and data:
select * from invoice where InvoiceID=19
InvoiceID invimagetype location
-----------------------------------
19 image/jpeg network
select * from Rel_Inv_Course where CourseID=4262
Rel_I_C_ID CourseID InvoiceID
----------------------------------
2255 4262 19
What I tried:
delete from [TAP].[dbo].Invoice
where InvoiceID = (select InvoiceID
from Rel_Inv_Course
where CourseID = 4262)
delete from Rel_Inv_Course
where CourseID = 4262
But I can't do this. I need to delete from both the rows of the tables with invoice id as 19. Please help.
As the comments said all you need to do is flip your delete statements and you should be good:
You may consider wraping them in a begin tran so you can check that your deletes only delete the data you want as well:
Begin Tran
DECLARE #INVOICEID INT
SET #INVOICE = (select InvoiceID from Rel_Inv_Course where CourseID=4262)
delete from Rel_Inv_Course where CourseID=4262
delete from [TAP].[dbo].Invoice where InvoiceID =(#INVOICEID)
--Select * from Rel_Inv_Course
--Select * from [dbo].Invoice
--If satisfied with deletes finally commit tran
--If not satisfied --> Rollback Tran
Commit Tran
This might be easier to explain with some sample data and DDL:
USE Sandbox;
GO
CREATE TABLE dbo.Parent (ID int NOT NULL,
SomeString varchar(100) NOT NULL);
GO
CREATE TABLE dbo.Child (ID int NOT NULL,
ParentID int NOT NULL,
AnotherString varchar(100) NOT NULL);
GO
ALTER TABLE dbo.Parent ADD CONSTRAINT PK_PID PRIMARY KEY CLUSTERED (ID);
ALTER TABLE dbo.Child ADD CONSTRAINT PK_CID PRIMARY KEY CLUSTERED (ID);
ALTER TABLE dbo.Child
ADD CONSTRAINT FK_PID
FOREIGN KEY (ParentID)
REFERENCES dbo.Parent (ID);
GO
INSERT INTO dbo.Parent (ID,
SomeString)
VALUES (1, 'sdfkgjbhasdfg'),
(2, 'sdfkjsdbhkf');
GO
INSERT INTO dbo.Child (ID,
ParentID,
AnotherString)
VALUES (1, 1, 'asdfkiashjbd'),
(2, 1, '#asldjasbhdk,'),
(3, 2, 'asfjasdfj');
GO
--Try to delete a row in Parent:
DELETE FROM dbo.Parent
WHERE ID = 2;
--No surprise it failed
GO
--Try to delete a row in child
DELETE FROM dbo.Child
WHERE ID = 2;
--This worked fine.
GO
--
--If we check, however, ParentID 1 and 2 are still in the table:
SELECT *
FROM dbo.Child;
--We want to delete ID 1 in parent, so we need to delete the other row
DELETE FROM dbo.Child
WHERE ParentID = 1;
--Now delete in Parent
DELETE FROM dbo.Parent
WHERE ID = 1;
GO
DROP TABLE dbo.Child;
DROP TABLE dbo.Parent;
You'll notice that the first delete on Parent failed, as it conflicts with the foreign key constraint. After, however, deleting all the rows in child for that ID, you can delete the parent row.
The same logic applies with your data. Delete the relevant rows in the child table first, and then you delete the data in your parent table. Alternatively, implement cascading, and then you simply need to delete the row in the parent, and the deletes will cascade down.
So If the "Type" is 0, i should be able to add my person in Table B, else not, but the "Type" column is not and shouldn't be in Table B.
You can do this with a foreign key constraint and some trickery.
First, set up a unique constraint on TableA for both type and person:
alter table TableA add constraint unq_TableA_type_person on TableA(type, person);
This allows you set to set up a foreign key constraint. However, you need a type column. For that, you can use a computed column:
alter table TableB add type_for_a as (0); -- it is always 0
Now, just use a foreign key constraint:
alter table TableB add constraint fk_tableA_type_person
foreign key (type_for_a, person) references tableA(type, person);
Voila! You have the constraint in place without having to write any code.
CREATE TABLE T1 (TypeID INT NOT NULL, people VARCHAR(50));
GO
CREATE TABLE T2 ( people VARCHAR(50));
GO
-- creating trigger to insert on the behalf when there is a particular type
CREATE TRIGGER dbo.AfterInsertTrigger
ON T1
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
declare #id int,
#someval char(1)
insert into dbo.T2
select i.people FROM Inserted i
where i.TypeID=0 -- checks only when the id is 0
END
GO
-- inserting people with different id s into Table1
INSERT T1 (TypeID, people) SELECT 1, 'A';
INSERT T1 (TypeID, people) SELECT 0, 'B';
GO
--selecting from tables see what got affected.
select * from T1
select *from T2
--Clean up
DROP TABLE T2;
DROP TABLE T1;
GO
I'm trying to execute the following trigger:
create trigger t23
on studies
after insert, update, delete
as
begin
REFERENCING NEW ROW NewStudent
FOR EACH ROW
WHEN (30 <= (SELECT SUM(credits) FROM Studies)
DELETE FROM NewStudent N
WHERE N.spnr = NewStudent.spnr
end
I'm trying to create a trigger which only inserts a student if the credits is < or == to '30'. The "Credits" is a type int.
I'm getting numerous errors trying to implement this trigger. I really have tried everything and i m out of options. Could someone who is expert in the field point me in the right direction?
The example "Using a DML AFTER trigger to enforce a business rule between the PurchaseOrderHeader and Vendor tables" in the CREATE TRIGGER MSDN documentation does exaclty what you're looking for:
USE AdventureWorks2008R2;
GO
IF OBJECT_ID ('Purchasing.LowCredit','TR') IS NOT NULL
DROP TRIGGER Purchasing.LowCredit;
GO
-- This trigger prevents a row from being inserted in the Purchasing.PurchaseOrderHeader table
-- when the credit rating of the specified vendor is set to 5 (below average).
CREATE TRIGGER Purchasing.LowCredit ON Purchasing.PurchaseOrderHeader
AFTER INSERT
AS
DECLARE #creditrating tinyint, #vendorid int;
IF EXISTS (SELECT *
FROM Purchasing.PurchaseOrderHeader p
JOIN inserted AS i
ON p.PurchaseOrderID = i.PurchaseOrderID
JOIN Purchasing.Vendor AS v
ON v.BusinessEntityID = p.VendorID
WHERE v.CreditRating = 5
)
BEGIN
RAISERROR ('This vendor''s credit rating is too low to accept new purchase orders.', 16, 1);
ROLLBACK TRANSACTION;
RETURN
END;
The key here is ROLLBACK TRANSACTION, just adapt the example to suit your need and you're done.
Edit: This should accomplish what you're looking for, but I have not tested it so your mileage may vary.
create trigger dbo.something after insert as
begin
if exists ( select * from inserted where sum(credits) > 30 )
begin
rollback transaction
raiserror ('some message', 16, 1)
end
end
Another edit, based on some assumptions (please note I wrote this script on the fly since I can't test it right now):
create table dbo.students
(
student_id int not null,
name varchar (50) not null
)
create table dbo.courses
(
course_id int not null,
name varchar (50) not null,
required_credits int not null
)
create table dbo.results
(
student_id int not null,
course_id int not null,
course_result int not null
)
create trigger dbo.check_student_results on dbo.results after insert as
(
declare #check int
select #check = count(*)
from inserted as a
join dbo.courses as b on b.course_id = a.course_id
where b.required_credits > a.course.result
if #check <> 0
begin
rollback transaction
raiserror('The student did not pass the course.', 16, 1)
end
)
This way when you insert records in the dbo.results table the constraint checks if the student has passed the course, and cancels the insertion if appropriate. However, it's better to check this things in the application layer.