SQL Trigger Delete oldest duplicate - sql

I have the following tables
HOLIDAY_DATE_TABLE:
USE BillingUI;
CREATE TABLE HOLIDAY_DATE_TABLE
(
HID INT IDENTITY PRIMARY KEY,
TABLE_NUMBER nchar(2) NOT NULL,
HOLIDAY_DATE nchar(8) NOT NULL,
FIELD_DESCRIPTION nVARchar(43) NULL,
);
tbl8_update_transactions:
USE BillingUI;
CREATE TABLE tbl8_update_transactions
(
TID INT IDENTITY PRIMARY KEY,
TABLE_NUMBER nchar(2) NOT NULL,
HOLIDAY_DATE nchar(8) NOT NULL,
FIELD_DESCRIPTION nVARchar(43) NULL,
HID int,
FOREIGN KEY (HID) REFERENCES HOLIDAY_DATE_TABLE (HID)
);
I'm trying to write a trigger for tbl8_update_transactions. Its goal is to identify records with duplicate foreign key values, and delete all instances of that row except for the most recent (identifiable by having the highest primary key number, as it's auto_incrementing).
What I have so far is....
CREATE TRIGGER tbl8_cleanup
ON tbl8_update_transactions
FOR INSERT
AS
BEGIN
SELECT HID, COUNT(*)
FROM tbl8_update_transactions
GROUP BY HID
HAVING COUNT(*) > 1;
DELETE FROM tbl8_update_transactions
WHERE COUNT(HID) > 1;
END;
I'm unsure as to how I can have the trigger delete all instances of a row that has duplicates except for the instance with the highest primary key number (TID).

I would use row_number() in a CTE:
with todelete as (
select t.*, row_number() over (partition by HID order by TID desc) as seqnum
from tbl8_update_transactions t
)
delete from todelete
where seqnum > 1;

Rather than scanning the entire table every time any activity occurs, why not be more targetted:
CREATE TRIGGER tbl8_cleanup
ON tbl8_update_transactions
INSTEAD OF INSERT --<-- Act before the new rows have been inserted
AS
BEGIN
DELETE FROM tbl8_update_transactions where HID in (select HID from inserted)
INSERT INTO tbl8_update_transactions (/* column list */)
SELECT /* column list */ from inserted
END;
So, before we insert any new rows, we first remove any rows that would be duplicates, and then we perform the actual insert we've been asked to do.
As a general rule, if your trigger code doesn't reference inserted and/or deleted, it's probably broken. See the documentation for more information.

Related

trigger for not inserting members doesnt work

I have this table
CREATE TABLE members
(
member_id INT PRIMARY KEY NOT NULL,
first_name VARCHAR(20),
last_name VARCHAR(20),
web_page VARCHAR(200),
e_mail VARCHAR(200),
cv VARCHAR(800),
dep_id INT,
teacher_id INT
);
and I want to create a trigger that if someone wants to insert a member which has a dep_id of 1 or 2 or 3.
And the teacher_id is different than NULL (as the teacher_id column is filled with either NULL or an id of another member)
I came up with this
CREATE TRIGGER employee_insup1
ON members
FOR INSERT, UPDATE
AS
DECLARE #dep_id INT, #teacher_id INT
SELECT #dep_id = i.dep_id, #teacher_id = i.teacher_id
FROM inserted i
IF ((#dep_id = 1) AND (#teacher_id != NULL))
BEGIN
RAISERROR('Teacher_id expects NULL',16,1)
ROLLBACK TRANSACTION
END
but after all if I try to insert a member with dep_id 1 and teacher_id 7(for example) it will be registered
You don't need a trigger for this. A check constraint is sufficient:
alter table members add constraint chk_members_dep_teacher
check (dep_id not in (1, 2, 3) or teacher_id is not null);
Specifically, this ensures that when dep_id is in one of those departments, then the teacher_id is not null. You might find the logic easier to follow as:
alter table members add constraint chk_members_dep_teacher
check (not (dep_id nt in (1, 2, 3) and teacher_id is null) );

Oracle Trigger Syntax Using Subquery

I'm trying to write a Trigger in Oracle Syntax which, upon entering a line into a particular table, checks that both values entered belong to some classification that is held in another table. My initial thought was to have a constraint on the table that included a subquery but Oracle doesn't seem to like that.
The select query I have written in the below works - but I'm not sure how to put it into a trigger - but essentially I need the trigger to ensure that EW1.OrgId and EW2.OrgId are the same. Any help is appreciated!
CREATE TABLE Organisation (
OrgId INTEGER PRIMARY KEY,
Name VARCHAR(40) NOT NULL
);
CREATE TABLE Person (
PersonId INTEGER PRIMARY KEY,
FirstName VARCHAR(45) NOT NULL,
LastName VARCHAR(45) NOT NULL
);
CREATE TABLE Employee (
PersonId INTEGER PRIMARY KEY REFERENCES PERSON (PersonId) ON DELETE CASCADE
);
CREATE TABLE Manager (
PersonId INTEGER PRIMARY KEY REFERENCES PERSON (PersonId) ON DELETE CASCADE
);
CREATE TABLE EnlistedWith (
OrgId INTEGER REFERENCES ORGANISATION (OrgId) ON DELETE CASCADE,
PersonId INTEGER REFERENCES PERSON (PersonId) ON DELETE CASCADE,
PRIMARY KEY(OrgId,PersonId)
);
CREATE TABLE SupervisedBy (
EmployeeId INTEGER REFERENCES Employee (PersonId) ON DELETE CASCADE,
ManagerId INTEGER REFERENCES Manager (PersonId) ON DELETE CASCADE,
CONSTRAINT PK_SupervisedBy PRIMARY KEY (EmployeeId, ManagerId)
);
CREATE TRIGGER SupervisorCompany
AFTER INSERT ON SupervisedBy
FOR EACH ROW
BEGIN
declare qty INTEGER := 0;
BEGIN
SELECT COUNT (*) into qty
FROM SupervisedBy SB
INNER JOIN EnlistedWith EW1 ON SB.ManagerId = EW1.PersonId
INNER JOIN EnlistedWith EW2 ON SB.EmployeeId = EW2.PersonId
and EW1.OrgId <> EW2.OrgId
IF qty <> 0
then Raise_Error (1234567, 'Manager and Employee are not Enlisted with same Organisation');
END IF;
END;
END;
You can refer to the columns of the owner of a Trigger using :NEW / :OLD. So, your Trigger could be re-written as
CREATE OR REPLACE TRIGGER supervisorcompany AFTER
INSERT
ON supervisedby FOR EACH ROW
DECLARE qty INTEGER := 0;
BEGIN
SELECT count (*)
INTO qty
FROM enlistedwith ew1
WHERE ew1.personid = :NEW.managerid
AND EXISTS
(
SELECT 1
FROM enlistedwith ew2
WHERE ew2.personid = :NEW.employeeid
AND ew1.orgid <> ew2.orgid ) ;
IF qty <> 0 THEN
raise_application_error (1234567, 'Manager and Employee are not Enlisted with same Organisation');
END IF;
END;
/
There's some guessing involved... Maybe something like this
CREATE TRIGGER SupervisorCompany
AFTER INSERT
ON SupervisedBy
FOR EACH ROW
BEGIN
IF (SELECT OrgId
FROM EnlistedWith
WHERE PersonId = New.ManagerId)
<>
(SELECT OrgId
FROM EnlistedWith
WHERE PersonId = New.EmployeeId) THEN
RAISE_ERROR(1234567, 'Manager and Employee are not Enlisted with same Organisation');
END IF;
END;
is what you want? It checks if the OrgId of the row where the PersonId equals the newly entered ManagerId is the same as the one for the newly entered EmployeeId. If not, your error is raised.
(Untested, as no DDL for the tables were provided.)

How to trigger a table to change the value of another table column

I've created three tables.
CREATE TABLE Clients
(
ClientID INT IDENTITY(1,1) PRIMARY KEY,
First_Name VARCHAR(50) NOT NULL,
Last_Name VARCHAR(50) NOT NULL,
)
CREATE TABLE Reservation
(
ReservationID INT IDENTITY(1,1) PRIMARY KEY,
ClientID INT FOREIGN KEY (ClientID) REFERENCES Clients(ClientID),
Reservation_paid VARCHAR(3) DEFAULT 'NO',
)
CREATE TABLE Payment
(
Payment_ID INT IDENTITY(1,1) PRIMARY KEY,
ClientID INT FOREIGN KEY (ClientID) REFERENCES Clients(ClientID),
ReservationID INT FOREIGN KEY (ReservationID) REFERENCES Reservation(ReservationID),
)
I would like to change the value of the column Reservation_paid to YES at the Reservation table whenever the Client does pay the reservation, and i want to do it automatically with trigger.
Example: If the ClientID at the Reservation table exists at the Payment table automatically the value of the Reservation_paid will set to YES.
Thank you in advance.
CREATE TRIGGER trgAfterInsert ON [dbo].[Payment]
FOR INSERT
AS
declare #ClientID int;
select #ClientID =i.ClientID from inserted i;
if update(ClientID)
UPDATE Reservation set Reservation_paid='Yes' WHERE
ClientID=#ClientID;
--PRINT 'AFTER INSERT trigger fired.'
After Insert Trigger should do something like this
UPDATE R
SET Reservation_paid = 'Yes'
FROM reservation R
WHERE EXISTS (SELECT 1
FROM INSERTED I
WHERE I.clientid = R.clientid
AND I.reservationid = R.reservationid)
CREATE TRIGGER trgAfterInsert ON [dbo].[Payment]
FOR INSERT
AS
declare #ClientID int;
select #ClientID =i.ClientID from inserted i;
insert into Reservation(ClientID,Reservation_paid)
values(#ClientID,'Yes');
--PRINT 'AFTER INSERT trigger fired.'
GO
Write a trigger that will work on table Reservation after any insert or update on ClientId column of table Payment. Then match the ClientID with ClientID column of Reservation table and update the corresponding Reservation_paid to YES.
Edit:
The trigger will be like this
CREATE TRIGGER `UpdateReservation_paid` AFTER INSERT OR UPDATE ON `Payment`
FOR EACH ROW BEGIN
AS
begin
update Reservation
SET Reservation_paid='YES'
Where NEW.ClientID = Reservation.ClientID
and NEW.ReservationID = Reservation.ReservationID
end

INSERT Conflict on Virtual Table SQL

I am having a problem on the INSERT because of a FK reference. The process goes like this:
I create the table Cuentas, and Cuentas_Con_RowNumber
I select from a huge table with over 3 million records. Because some are repeated and I need to store only 1 "cuenta", I made the tempDB. I have to do this, because on the huge db there are many records with the same Cuenta_Nro with different transactions, and I just need one.
I select from the tempDB all the columns but the RowNumber and then insert it into the Cuentas table.
The problem is that the tempDB Pais (country) column is not a FK which references to the Paises (countries) table, and on the original table (Cuentas) it does, therefore, it crashes.
Code:
CREATE TABLE Paises
(
Pais_Id numeric(18,0) PRIMARY KEY NOT NULL,
Pais_Nombre varchar(255) NOT NULL
)
CREATE TABLE Cuentas
(
Cuenta_Nro numeric(18,0) PRIMARY KEY NOT NULL,
Cuenta_Estado varchar(255),
Cuenta_Moneda varchar(255) DEFAULT 'Dolar',
Cuenta_Tipo numeric(18,0)
FOREIGN KEY REFERENCES Tipo_De_Cuentas(Tipo_De_Cuenta_Id),
Cuenta_PaisOrigen numeric(18, 0)
FOREIGN KEY REFERENCES Paises(Pais_Id),
Cuenta_PaisAsignado numeric(18, 0)
FOREIGN KEY REFERENCES Paises(Pais_Id),
Cuenta_Fec_Cre datetime,
Cuenta_Fec_Cierre datetime,
Cuenta_Tarjeta numeric(18, 0)
FOREIGN KEY REFERENCES Tarjetas(Tarjeta_Nro),
Cuenta_Cliente numeric(18, 0)
FOREIGN KEY REFERENCES Clientes(Cliente_Id)
)
CREATE TABLE #Cuentas_Con_RowNumer
(
Cuenta_Nro numeric(18,0) PRIMARY KEY NOT NULL,
Cuenta_Estado varchar(255),
Cuenta_PaisOrigen numeric(18,0)),
Cuenta_Fec_Cre datetime,
Cuenta_Fec_Cierre datetime,
Cuenta_Cliente numeric(18,0),
Cuenta_Tarjeta numeric(18,0),
RowNumber int
)
INSERT INTO #Cuentas_Con_RowNumer
SELECT *
FROM (SELECT
Maestro.Cuenta_Numero, Maestro.Cuenta_Estado, Maestro.Cuenta_Pais_Codigo,
Maestro.Cuenta_Fecha_Creacion, Maestro.Cuenta_Fecha_Cierre, Clientes.Cliente_Id, Maestro.Tarjeta_Numero,
ROW_NUMBER() OVER (PARTITION BY Maestro.Cuenta_Numero ORDER BY Maestro.Cuenta_Numero) AS RowNumber
FROM gd_esquema.Maestra Maestro, dbo.Clientes
WHERE
Clientes.Cliente_Apellido = Maestro.Cli_Apellido AND
Clientes.Cliente_Nombre = Maestro.Cli_Nombre) AS a
WHERE a.RowNumber = '1'
INSERT INTO Cuentas
(
Cuenta_Nro, Cuenta_Estado, Cuenta_PaisOrigen, Cuenta_Fec_Cre,
Cuenta_Fec_Cierre, Cuenta_Cliente, Cuenta_Tarjeta
)
SELECT
Cuenta_Nro, Cuenta_Estado, Cuenta_PaisOrigen, Cuenta_Fec_Cre,
Cuenta_Fec_Cierre, Cuenta_Cliente, Cuenta_Tarjeta
FROM #Cuentas_Con_RowNumer
The error message is:
Instrucción INSERT en conflicto con la restricción FOREIGN KEY "FK__Cuentas__Cuenta___24B338F0". El conflicto ha aparecido en la base de datos "GD1C2015", tabla "dbo.Paises", column 'Pais_Id'.
The issue is because Maestro.Cuenta_Pais_Codigo column is being pulled from gd_esquema.Maestra table which in turn is going as Cuenta_PaisOrigen in target table and has a foreign key defined.
There will be some records which are being selected for insert Cuentas table that doesn't have a matching Pais_Id record in dbo.Paises table.
You can add a inner join as below and check the results as :
INSERT INTO #Cuentas_Con_RowNumer
SELECT *
FROM (SELECT
...
FROM gd_esquema.Maestra Maestro
inner join dbo.Clientes on
Clientes.Cliente_Apellido = Maestro.Cli_Apellido AND
Clientes.Cliente_Nombre = Maestro.Cli_Nombre
inner join Paises P on Maestro.Cuenta_Pais_Codigo = P.Pais_Id
) AS a
WHERE a.RowNumber = '1'

create table with auto increment as first col and data type as second

maybe I am over thinking this these are the instructions
create four new tables: my_interests, my_professions, my_seeking and my_status. These tables should contain two columns: one for an id and another for the data value. Populate these from the appropriate columns in the my_contacts table. Once your new tables are ready, you can replace the original data columns with id numbers matching the applicable id values in your new my_professions and my_status tables.
SO THE WAY I READ THE FIRST IS I HAVE THE FIRST COL AS AN AUTO INCREMENT PRIMARY KEY, THE NEXT VALUE WOULD BE THE DATA TYPE, I AM STARTING WITH MY_STATUS FIRST AND THE TYPES WOULD BE
COMMITED_RELATIONSHIP
DIVORCED
MARRIED
SINGLE
WIDOWED
AND MY AUTO_INC NUMBER WOULD CORRESPOND TO THE ID OF DATA, IN OTHER WORDS
01**COMMITED
02**DIVORCED
03** AND SO ON
AM I CORRECT IN THE WAY I AM READING THE INSTRUCTIONS?
AND IF SO NOT QUITE SURE HOW TO DO THIS, I KNOW HOW TO CREATE THE TABLE, AND I UNDERSTAND INSERT INTO AND VALUES, BUT HOW DO I INSERT THE VALUES AND AUTO INCREMENT? I REALLY DISLIKE PROGRAMMING :(
thanks in advance
Create table my_status (status_id int NOT NULL AUTO_INCREMENT,status_type varchar(20), PRIMARY KEY (status_id)); To Create
insert into my_status (status_type) values("Single"),("Divorced"),("Married"); to insert
Create table my_status (status_id int NOT NULL AUTO_INCREMENT,status_type varchar(20), PRIMARY KEY (status_id)); To Create
insert into my_status (status_type) values("Single"),("Divorced"),("Married"); to insert
Possible Answer to your 2nd question
CREATE TABLE `my_status` (
`status_id` int(11) NOT NULL auto_increment,
`status_type` varchar(30),PRIMARY KEY(`status_id`) );
CREATE TABLE `my_profession` (
`profession_id` int(11) NOT NULL auto_increment,
`profession_type` varchar(30),PRIMARY KEY(`profession_id`) );
CREATE TABLE `my_contacts` (
`id` int(11) NOT NULL auto_increment,
`last_name` varchar(30) ,
`first_name` varchar(20) ,
`email` varchar(50) ,
`gender` char(1),
`birthday` date ,
`profession_id` int(11),
`location` varchar(50),
`status_id` int(11),
`interests` varchar(200),
`seeking` varchar(200),
PRIMARY KEY (`id`),
FOREIGN KEY (status_id)
REFERENCES my_status(status_id),
FOREIGN KEY (profession_id)
REFERENCES my_profession(profession_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
insert into my_status (status_type) values("Single"),("Divorced"),("Married");
insert into my_profession (profession_type) values("Writer"),("CA"),("Developer");
INSERT INTO `my_contacts` (`last_name`,`first_name`,`email`,`gender`,`birthday`,`profession_id`,`location`,`status_id`,`interests`,`seeking`) VALUES ('Anderson','Jillian','jill_anderson# \nbreakneckpizza.com','F','1980-09-05',1,'Palo Alto, CA',1,'kayaking, reptiles','relationship, friends');
INSERT INTO `my_contacts` (`last_name`,`first_name`,`email`,`gender`,`birthday`,`profession_id`,`location`,`status_id`,`interests`,`seeking`) VALUES ('Kenton','Leo','lkenton#starbuzzcoffee.com','M','1974-01-10',2,'San Francisco, CA',2,'women','women to date');
INSERT INTO `my_contacts` (`last_name`,`first_name`,`email`,`gender`,`birthday`,`profession_id`,`location`,`status_id`,`interests`,`seeking`) VALUES ('McGavin','Darrin',' captainlove#headfirsttheater.com','M','1966-01-23',3,'San Diego, CA',3,'sailing, fishing, yachting','women for casual relationships');
INSERT INTO `my_contacts` (`last_name`,`first_name`,`email`,`gender`,`birthday`,`profession_id`,`location`,`status_id`,`interests`,`seeking`) VALUES ('xyz','abc',' xyz#abc.com','F','1966-01-24',1,'San Diego, CA',3,'sailing, fishing, yachting, golfing','women for casual relationships');
select * from my_contacts;
select * from my_status;
select * from my_profession;
SELECT * FROM my_contacts WHERE status_id IN
(SELECT status_id FROM my_status WHERE status_type = 'Married');
Hope this is what you want!!!
UPDATE my_contacts
SET status='1'
WHERE status='committed relationship';
UPDATE my_contacts
set status= '2'
where status='divorced';
UPDATE my_contacts
set status= '3'
where status='married';
UPDATE my_contacts
set status= '4'
where status='single';
UPDATE my_contacts
set status= '5'
where status='widowed';
THANKS EVERYONE!! (yeah that time I shouted, lol!)